Javascript 将Observable与async/await结合使用是否是一种良好的做法?
我使用angular 2公共http返回一个可观察的,但我面临一个问题,当我使用嵌套的可观察调用时,我的代码就像一个网格:Javascript 将Observable与async/await结合使用是否是一种良好的做法?,javascript,angular,typescript,promise,observable,Javascript,Angular,Typescript,Promise,Observable,我使用angular 2公共http返回一个可观察的,但我面临一个问题,当我使用嵌套的可观察调用时,我的代码就像一个网格: this.serviceA.get().subscribe((res1: any) => { this.serviceB.get(res1).subscribe((res2: any) => { this.serviceC.get(res2).subscribe((res3: any) => { }) }) })
this.serviceA.get().subscribe((res1: any) => {
this.serviceB.get(res1).subscribe((res2: any) => {
this.serviceC.get(res2).subscribe((res3: any) => {
})
})
})
现在我想使用async/await来避免这种情况,但是async/await只能在有承诺的情况下工作。我知道“可观察”可以转化为“承诺”,但正如我所知,这不是一个好的实践。那我在这里该怎么办
顺便说一句,如果有人能给我一个示例代码来解决这个问题,用async/await:D按顺序链接观测值,就像你在代码中想做的那样,那就太好了
关于您的代码示例,如果您希望链接观察对象(在前一次发射后触发另一次),请为此使用flatMap
(或switchMap
):
this.serviceA.get()
.flatMap((res1: any) => this.serviceB.get())
.flatMap((res2: any) => this.serviceC.get())
.subscribe( (res3: any) => {
....
});
与嵌套相比,这是一个更好的实践,因为这将使事情更清楚,并帮助您避免回调地狱,可观察和承诺本来应该帮助防止回调地狱
也可以考虑使用<代码>开关图< /C> >而不是<代码>平面图< /> >,基本上,如果第一个发出新的值,它将允许“取消”其他请求。例如,如果触发rest的第一个可观察对象是某个按钮上的某个单击事件,那么使用起来很好
如果您不需要各种请求轮流等待,您可以使用forkJoin
或zip
一次启动它们,请参阅以获取详细信息和其他细节
角度“异步”管道和可观测对象配合良好 关于可观测值和角度,您可以在角度模板中完美地使用
|async
管道,而不是在组件代码中订阅可观测值,以获取该可观测值发出的值
ES6异步/等待和承诺而不是可观察? 如果您不想直接使用Observable,只需在Observable上使用
.toPromise()
,然后使用一些异步/等待指令即可
如果您的Observable应该只返回一个结果(就像基本API调用一样),那么Observable可以被视为相当于承诺
然而,考虑到Observable已经提供的所有东西,我不确定是否有必要这样做(读者:欢迎有启发性的反例!)。我更倾向于尽可能使用可观测数据作为训练练习
一些有趣的博客文章(还有很多其他的): toPromise函数实际上有点棘手,因为它不是 实际上是一个“操作员”,而不是RxJS特定的操作方式 订阅一个可观察到的并用承诺来包装它承诺 一旦 可观察完成。这意味着如果可观测物体发出 值“hi”然后等待10秒,然后返回 promise将在解析“hi”之前等待10秒。如果可以观察到 没有完成,承诺就永远无法实现 注意:使用toPromise()是一种反模式,除非您 处理期望承诺的API,例如async await (强调矿山)
你要求的例子 顺便说一句,如果有人能给我一个示例代码来解决这个问题,那就太好了 这与async/await:D有关 示例如果您真的想这样做(可能有一些错误,现在无法检查,请随时更正) 在您可以同时启动所有请求的情况下,
等待Promise.all()
这应该更有效,因为所有调用都不依赖于彼此的结果。(就像forkJoin
处理可观察对象一样)
由于@Pac0已经很好地阐述了各种解决方案,因此我将添加稍微不同的角度 混合承诺和观察 我个人更喜欢不要将承诺和观察值混为一谈——这是使用async await和观察值时得到的结果,因为尽管它们看起来相似,但它们非常不同
- 承诺总是异步的,不一定是可观察的
- 承诺仅代表1个值,可观测值为0、1或多个
- 承诺的用途非常有限,例如,你不能取消它们(暂且不提下一个建议),可观察到的在使用上要强大得多(你可以用它们管理多个WS连接,用承诺试试)
- 他们的API差别很大
承诺在英语中的使用
现在,即使有时两者都有效,特别是<强>角时,我认为应该考虑尽可能远的RxJS < /强>。原因是:
- Angular API的很大一部分使用了可观察的对象(路由器,http…),因此使用RxJS有一种是顺流的,而不是逆流的(没有双关语的意思),否则在弥补RxJS提供的失去的可能性的同时,必须始终转换为承诺
- Angular拥有强大的
管道,它允许您构建整个应用程序数据流,您可以对其进行过滤、组合和任何修改,而无需中断来自服务器的数据流,无需进行任何查询或订阅。这样,您就不需要展开数据或将其分配给一些辅助变量,数据只是从服务通过可观察对象直接流到模板,这非常漂亮async
// Warning, probable anti-pattern below
async myFunction() {
const res1 = await this.serviceA.get().toPromise();
const res2 = await this.serviceB.get().toPromise();
const res3 = await this.serviceC.get().toPromise();
// other stuff with results
}
async myFunction() {
const promise1 = this.serviceA.get().toPromise();
const promise2 = this.serviceB.get().toPromise();
const promise3 = this.serviceC.get().toPromise();
let res = await Promise.all([promise1, promise2, promise3]);
// here you can retrieve promises results,
// in res[0], res[1], res[2] respectively.
}
this.result$ = Observable.forkJoin(
this.serviceA.get(),
this.serviceB.get(),
this.serviceC.get()
);
this.result$.subscribe(([resA, resB, resC]) => ...)
async getSomethingById(id: number): Promise<Something> {
return await this.http.get<Something>(`api/things/${id}`).toPromise();
}
async someFunc(): Promise {
console.log(await getSomethingById(1));
}