Angular - 创建从服务器检索数据并将它们发送到使用它的组件的服务的正确方法是什么?
Angular - Which is the proper way to create a service that retrives data from a server and send them to a component that uses it?
我正在使用 Angular (v6.0.0) 开发网络应用程序。我有一个公开 API 以检索产品的服务器。一切正常,但我想知道我所做的以及我如何做的是否正确。如果没有,我想知道是否有人可以帮助我改进我的代码。
以下是我的 HttpService,我将其用作 HttpClient 的扩展,因为我必须在请求的 URL 中设置使用的语言:
HttpService
import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from '../../../environments/environment';
import { TranslateService } from '@ngx-translate/core';
@Injectable({
providedIn: 'root'
})
export class HttpService {
constructor(
private http: HttpClient,
private translate: TranslateService
) { }
/**
* General GET request
*
* @param {string} url URL of the request
* @param {HttpParams} [params]
* @returns {Promise<any>}
* @memberof HttpService
*/
async get(url: string, params?: HttpParams): Promise<any> {
return await this.http.get<any>(`${environment.apiURL}${this.translate.getDefaultLang()}/${url}`, { params: params }).toPromise();
}
}
然后我有 ProductService:
import { Injectable } from '@angular/core';
import { HttpService } from '../http/http.service';
import { Product } from 'src/app/models/product';
import { HttpParams } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ProductService {
constructor(
private httpService: HttpService
) { }
async getProductsByCategory(categoryId: string): Promise<Product[]> {
let res = await this.httpService.get('products', new HttpParams().set('category', categoryId).set('perPage', '1000'));
return res.data;
}
}
这里注意我知道products的数组是res.data
.
现在,在我使用 ProductService
的组件中,我执行以下操作:
this.products = await this.productService.getProductsByCategory(ID);
正如我在问题开头所说的那样,一切似乎都按预期工作得很好,但我对我读过的所有关于 promises 以及如何使用它们的文章感到困惑,所以我想问你们这是否是使用 promises 的正确方法,或者我是否需要改进我的代码。
感谢您的回复!
我在这里唯一的建议是不要使用 Promise,因为 Observable 可以很容易地用于您在代码中使用这些服务的地方。
在我看来,您的 HttpService
可以转换为 http 拦截器。尤其是当您只有一个 API 端点时。
在 ProductService
中,我会 return 一个可观察的,而不是一个承诺,主要有两个原因:
Observable 是可取消的。因此,也许一个请求需要更长的时间并且用户改变了主意,您希望能够取消该请求并且服务器停止处理它(如果它对服务器来说是一些密集的事情)。
您的服务可能会演变为在某些情况发生变化且承诺无法做到这一点时推送新项目。例如,您有一个具有 items$
和一些 add
/delete
方法的通用回购服务。您可以更改服务以在 add
/delete
正常工作时立即更新项目,如本例所示:
我会给你一个在我们的项目中使用的示例代码。
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../../../environments/environment';
import { Observable } from 'rxjs';
import { httpOptions } from '../../http-options';
import { Content } from '../../content.model';
@Injectable({
providedIn: 'root'
})
export class PredefinedContentService {
private reportPredefinedContentApi = `${environment.baseUrl}/report/report-predefined-contents`;
constructor(private httpClient: HttpClient) { }
getList(reportSectionId : number) : Observable<Content[]>{
return this.httpClient.get<Content[]>(`${this.reportPredefinedContentApi}/${reportSectionId}`, httpOptions);
}
}
在component.ts,
reportSectionId: number;
contents: Content[] = [];
constructor(private predefinedTextService: PredefinedContentService) {}
getContentList() {
this.predefinedTextService
.getList(this.reportSectionId)
.subscribe(result => {
this.contents = result;
},error => {
console.log(error)
});
}
我正在使用 Angular (v6.0.0) 开发网络应用程序。我有一个公开 API 以检索产品的服务器。一切正常,但我想知道我所做的以及我如何做的是否正确。如果没有,我想知道是否有人可以帮助我改进我的代码。
以下是我的 HttpService,我将其用作 HttpClient 的扩展,因为我必须在请求的 URL 中设置使用的语言:
HttpService
import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from '../../../environments/environment';
import { TranslateService } from '@ngx-translate/core';
@Injectable({
providedIn: 'root'
})
export class HttpService {
constructor(
private http: HttpClient,
private translate: TranslateService
) { }
/**
* General GET request
*
* @param {string} url URL of the request
* @param {HttpParams} [params]
* @returns {Promise<any>}
* @memberof HttpService
*/
async get(url: string, params?: HttpParams): Promise<any> {
return await this.http.get<any>(`${environment.apiURL}${this.translate.getDefaultLang()}/${url}`, { params: params }).toPromise();
}
}
然后我有 ProductService:
import { Injectable } from '@angular/core';
import { HttpService } from '../http/http.service';
import { Product } from 'src/app/models/product';
import { HttpParams } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ProductService {
constructor(
private httpService: HttpService
) { }
async getProductsByCategory(categoryId: string): Promise<Product[]> {
let res = await this.httpService.get('products', new HttpParams().set('category', categoryId).set('perPage', '1000'));
return res.data;
}
}
这里注意我知道products的数组是res.data
.
现在,在我使用 ProductService
的组件中,我执行以下操作:
this.products = await this.productService.getProductsByCategory(ID);
正如我在问题开头所说的那样,一切似乎都按预期工作得很好,但我对我读过的所有关于 promises 以及如何使用它们的文章感到困惑,所以我想问你们这是否是使用 promises 的正确方法,或者我是否需要改进我的代码。
感谢您的回复!
我在这里唯一的建议是不要使用 Promise,因为 Observable 可以很容易地用于您在代码中使用这些服务的地方。
在我看来,您的 HttpService
可以转换为 http 拦截器。尤其是当您只有一个 API 端点时。
在 ProductService
中,我会 return 一个可观察的,而不是一个承诺,主要有两个原因:
Observable 是可取消的。因此,也许一个请求需要更长的时间并且用户改变了主意,您希望能够取消该请求并且服务器停止处理它(如果它对服务器来说是一些密集的事情)。
您的服务可能会演变为在某些情况发生变化且承诺无法做到这一点时推送新项目。例如,您有一个具有
items$
和一些add
/delete
方法的通用回购服务。您可以更改服务以在add
/delete
正常工作时立即更新项目,如本例所示:
我会给你一个在我们的项目中使用的示例代码。
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../../../environments/environment';
import { Observable } from 'rxjs';
import { httpOptions } from '../../http-options';
import { Content } from '../../content.model';
@Injectable({
providedIn: 'root'
})
export class PredefinedContentService {
private reportPredefinedContentApi = `${environment.baseUrl}/report/report-predefined-contents`;
constructor(private httpClient: HttpClient) { }
getList(reportSectionId : number) : Observable<Content[]>{
return this.httpClient.get<Content[]>(`${this.reportPredefinedContentApi}/${reportSectionId}`, httpOptions);
}
}
在component.ts,
reportSectionId: number;
contents: Content[] = [];
constructor(private predefinedTextService: PredefinedContentService) {}
getContentList() {
this.predefinedTextService
.getList(this.reportSectionId)
.subscribe(result => {
this.contents = result;
},error => {
console.log(error)
});
}