我一直在查看 Angular 文档,为什么 httpClient 使用观察者,但没有找到好的答案。 我的问题是因为我正在开发一个大型项目,我们正在寻找最具可扩展性的方式来构建代码。 我们希望编写尽可能干净的代码,遵循所有可能的干净代码规则,但我们无法理解处理 http 请求的最佳方法是什么。
首先,我们有2种可能性。
示例:
fruits.component.ts(.component 看起来很干净)
apples: any;
bananas: any;
constructor(
private fruitsService: FruitService
) { }
ngOnInit(): void {
this.loadData()
}
loadData(){
console.log('before get apples');
this.apples = this.getApples();
console.log('before get bananas');
this.bananas = this.getBananas();
}
async getApples(){
console.log('1');
let apples = await this.fruitsService.getApples();
console.log('2');
return apples;
}
async getBananas(){
console.log('1');
let bananas = await this.fruitsService.getBananas();
console.log('2');
return bananas;
}
fruits.service(这看起来很脏)
export class FruitService{
constructor(private httpClient: HttpClient) { }
getApples(){
let url = `${Global.url}/api/apples`
return new Promise(async (res) => {
this.httpClient.get(url, {
headers: {
'Content-Type': 'application/json'
}
}).subscribe(data => res(data));
})
}
getBananas(){
let url = `${Global.url}/api/bananas`
return new Promise(async (res) => {
this.httpClient.get(url, {
headers: {
'Content-Type': 'application/json'
}
}).subscribe(data => res(data));
})
}
}
结果控制台.logs
fruits.component.ts
apples: any;
bananas: any;
constructor(
private fruitsService: FruitService
) { }
ngOnInit(): void {
this.loadData()
}
loadData(){
this.apples = this.getApples();
this.bananas = this.getBananas();
}
getBananas(){
this.fruitsService.getBananas().subscribe({
next: (res) => {
if(res?.status == ServerStatus.SUCCESSFUL){
this.bananas = res?.bananas
}
},
error: (err) => {
this.snackBar.open("Error Bananas", "Cerrar", {
duration: 5000,
panelClass: ['incorrect-snackbar']
});
}
})
}
getApples(){
this.fruitsService.getApples().subscribe({
next: (res) => {
if(res?.status == ServerStatus.SUCCESSFUL){
this.apples = res?.apples
}
},
error: (err) => {
this.snackBar.open("Error Apples", "Cerrar", {
duration: 5000,
panelClass: ['incorrect-snackbar']
});
}
})
}
fruits.service(服务看起来非常干净,我不重复一个非常健壮的结构 )
export class FruitService{
constructor(private httpClient: HttpClient) { }
getBananas(): Observable<any>{
return this.httpClient.get(`${Global.url}/api/bananas`, {
headers: {
'Content-Type': 'application/json'
}
});
}
getApples(): Observable<any>{
return this.httpClient.get(`${Global.url}/api/apples`, {
headers: {
'Content-Type': 'application/json'
}
});
}
}
干净代码的问题: 不遵循“单一责任原则” 例如,如果我想要带有数据的实际表单,我们需要等待来自端点的数据...... 我们需要在订阅的“下一个”中执行此操作。 例如:
getBananas(){
this.fruitsService.getBananas().subscribe({
next: (res) => {
if(res?.status == ServerStatus.SUCCESSFUL){
this.bananas = res?.bananas
this.setValuesForm();
}
},
error: (err) => {
this.snackBar.open("Error Bananas", "Cerrar", {
duration: 5000,
panelClass: ['incorrect-snackbar']
});
}
})
}
setValuesForm(){
this.formGroupBananas.patchValue(this.bananas);
}
然后进入获取香蕉,我们获取香蕉并调用函数来设置 formGroup 中的值(2 个职责)
如果有人可以通过文档帮助我们找到一种好方法来做到这一点,我们将非常感激:)
我们实际上使用了第二种方式,但这会导致代码整洁的问题,我们需要一种更具可扩展性的方式
Angular 的 HttpClient 使用 Observables 而不是 Promise,原因有几个与 Angular 框架内的灵活性、功能和集成相关的关键原因。主要原因如下:
惰性执行:Observables 是惰性的,这意味着它们在被订阅之前不会执行。这允许创建潜在的复杂操作链,这些操作链在明确请求之前实际上不会执行任何工作。
随着时间的推移多个值:Observables 可以随着时间的推移处理多个值,这使得它们适合需要处理数据流或多个事件的场景。相反,Promise 处理单个值或错误。
运算符和函数式编程:Observables 附带了来自 JavaScript Reactive Extensions (RxJS) 库的各种运算符(如映射、过滤器、合并等)。这些运算符支持强大的函数式编程技术来转换和组合数据流。
取消:Observables 支持取消,这意味着你可以取消订阅 Observable 以停止监听数据流。这在 Angular 中特别有用,可以在组件被销毁或用户离开视图时防止内存泄漏和不必要的网络请求。
一致性和集成:Angular 在整个框架中使用 Observables 来进行各种异步操作,例如事件处理、表单和路由。通过在 HttpClient 中使用 Observables,Angular 保持了处理异步操作的一致方法,这可以简化学习曲线并提高代码一致性。
错误处理:Observables 通过 catchError 和 retry 等运算符提供更强大的错误处理功能。这允许开发人员以声明性和可组合的方式处理错误并重试失败的请求。