Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/31.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 将Observable与async/await结合使用是否是一种良好的做法?_Javascript_Angular_Typescript_Promise_Observable - Fatal编程技术网

Javascript 将Observable与async/await结合使用是否是一种良好的做法?

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) => { }) }) })

我使用angular 2公共http返回一个可观察的,但我面临一个问题,当我使用嵌套的可观察调用时,我的代码就像一个网格:

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
    管道,它允许您构建整个应用程序数据流,您可以对其进行过滤、组合和任何修改,而无需中断来自服务器的数据流,无需进行任何查询或订阅。这样,您就不需要展开数据或将其分配给一些辅助变量,数据只是从服务通过可观察对象直接流到模板,这非常漂亮
不过,在某些情况下,承诺仍然会发光。例如,我在rxjs TypeScript类型中缺少的是single的概念。如果您正在创建一个供其他人使用的API,那么返回Observable并不能说明一切:您将收到1个值,多个值,还是仅仅完成?你必须写评论来解释它。另一方面,在这种情况下,允诺有更明确的合同。它将始终使用1值进行解析,或使用错误进行拒绝
// 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));
}