4 回答
TA贡献1772条经验 获得超8个赞
首先,你的代码可以工作,这很好——你可以保持原样,一切都会好起来的。
另一方面,有一种多重改进的方法将在未来帮助您和您的同事:
尝试将与 http 相关的逻辑移至服务中,而不是在组件中调用 http - 这将帮助您将代码拆分为与视图相关的逻辑和与业务/获取/转换相关的逻辑。
尽量避免嵌套
subscribe
s - 您不仅会忽略Observable
s 的强大功能,而且还会将代码绑定到某个流程,而无法在应用程序中的某个地方重用这些行。返回Observable
可能会帮助您“共享”请求的结果或以某种方式对其进行转换。flatMap/mergeMap
,concatMap
并switchMap
以不同的方式工作,使您能够按照自己想要的方式控制行为。不过,由于http.get()
它们的工作原理几乎相似,因此最好尽快开始学习那些组合运算符。考虑一下在这种情况下您将如何处理错误 - 如果您的第一次调用将导致错误,会发生什么?
Observable
有一个强大的机制来处理它们,同时.subscribe
允许您仅以一种方式处理错误。
使用的示例switchMap
:
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-root',
templateUrl: 'app/app.component.html'
})
export class AppComponent {
loadedCharacter: {};
constructor(private http: HttpClient) {}
ngOnInit() {
const character$ = this.http.get('/api/people/1').pipe(
tap(character => this.characterWithoutHomeworld = character), // setting some "in-between" variable
switchMap(character => {
return this.http.get(character.homeworld).pipe(
map(homeworld => {
return {
...character,
homeworld: homeworld
}
}
)
)
}),
catchError(errorForFirstOrSecondCall => {
console.error('An error occurred: ', errorForFirstOrSecondCall);
// if you want to handle this error and return some empty data use:
// return of({});
// otherwise:
throw new Error('Error: ' + errorForFirstOrSecondCall.message);
})
);
// you can either store this variable as `this.character$` or immediately subscribe to it like:
character$.subscribe(loadedCharacter => {
this.loadedCharacter = loadedCharacter;
}, errorForFirstOrSecondCall => {
console.error('An error occurred: ', errorForFirstOrSecondCall);
})
}
}
TA贡献1810条经验 获得超4个赞
2 嵌套订阅永远不是一个可行的方法。我推荐这种方法:
this.http.get('/api/people/1').pipe(
switchMap(character => this.http.get(character.homeworld).pipe(
map(homeworld => ({ ...character, homeworld })),
)),
).subscribe(character => this.loadedCharacter = character);
编辑:对于你的大学
this.http.get('/api/people/1').pipe(
switchMap(character => this.http.get(character.university).pipe(
map(university => ({ ...character, university})),
)),
).subscribe(character => this.loadedCharacter = character);
甚至连锁大学和家乡的请求
this.http.get('/api/people/1').pipe(
switchMap(character => this.http.get(character.homeworld).pipe(
map(homeworld => ({ ...character, homeworld })),
// catchError(err => of({ ...character, homeworld: dummyHomeworld })),
)),
switchMap(character => this.http.get(character.university).pipe(
map(university => ({ ...character, university})),
)),
).subscribe(character => this.loadedCharacter = character);
TA贡献1827条经验 获得超9个赞
switchmap您可以尝试使用和来更轻松地进行链接和错误处理的解决方案forkJoin。这将有助于保持代码干净,以防链不断增长成深嵌套。
this.http
.get("/api/people/1'")
.pipe(
catchError((err) => {
// handle error
}),
switchMap((character) => {
return forkJoin({
character: of(character),
homeworld: this.http.get(character.homeworld)
});
})
)
.subscribe(({ character, homeworld }) => {
character.homeworld = homeworld;
this.loadedCharacter = character;
});
编辑:场景 2
this.http
.get("/api/people/1")
.pipe(
catchError((err) => {
console.log("e1", err);
}),
switchMap((character) => {
return forkJoin({
character: of(character),
homeworld: this.http.get(character.homeworld).pipe(
catchError((err) => {
console.log("e2", err);
})
)
});
})
)
.subscribe(({ character, homeworld }) => {
character.homeworld = homeworld;
this.loadedCharacter = character;
});
您可以链接捕获错误或添加单独的错误处理函数,而无需调用下一个 API 调用。但我建议将后端逻辑抽象为角度服务并使用此方法。这将有助于保持易于阅读的结构。
TA贡献1875条经验 获得超5个赞
您可以通过检查状态码来检查第一次请求是否成功:
ngOnInit() {
this.http.get('/api/people/1').subscribe((character: HttpResponse<any>) => {
// here you should look for the correct status code to check, in this example it's 200
if (character.status === 200) {
this.http.get(character.homeworld).subscribe(homeworld => {
character.homeworld = homeworld;
this.loadedCharacter = character;
});
} else {
// character is gonna contain the error
console.log(character)
}
});
}
添加回答
举报