【问题标题】:Convert async function to RxJs Observable将异步函数转换为 RxJs Observable
【发布时间】:2021-10-03 09:33:23
【问题描述】:

防止写一定量的代码,比如这个例子:

    ...
    public getDataSet() : Observable<any>
    {
        return new Observable(observer => {
            if (this.dataset === undefined) {
                this.get().subscribe(data => {
                    this.dataset = new DataSet(data) ;
                    observer.next(this.dataset)
                    observer.complete() ;
                }) ;
            }
            else {
                observer.next(this.dataset)
                observer.complete() ;
            }
        }) ;
    }

我想使用 async/await 功能,但仍返回一个 Observable 以在使用异步数据收集服务时保持一致。

因此,根据 RxJs 的文档,我应该使用 from() 运算符。 https://www.learnrxjs.io/learn-rxjs/operators/creation/from

这是我尝试实现的(看起来更简洁):

import { Observable, from } from 'rxjs' ;
...
        return from(async () => { // ✘ error
            if (this.dataset === undefined) this.dataset = new DataSet(await this.get().toPromise()) ;
            return this.dataset ;
        }) ;

但是,TypeScript 不能将 async () =&gt; {} 识别为 ObservableInput,但它确实识别了这个:

import { Observable, from } from 'rxjs' ;
...
        return from(new Promise((resolve) => { // ✔ valid
            if (this.dataset === undefined) {
                this.get().toPromise().then(data => {
                    this.dataset = new DataSet(data) ;
                    resolve(this.dataset) ;
                }) ;
            }
            else resolve(this.dataset) ;
        })) ;

不过,JavaScript 的 async 关键字让函数总是返回一个 Promise。

console.log((async () => {}) ())
// Promise {}

有没有办法让from() RxJs 操作员接受异步承诺?

【问题讨论】:

    标签: angular typescript async-await rxjs observable


    【解决方案1】:

    异步函数在调用时返回一个承诺,在此之前它只是一个函数。

    function fromAsyncFunction(): Observable<number> {
        return from((async () => {
          return 1;
        })()); // Call it
    }
    

    【讨论】:

    • 该死的,当我收到答案时我才意识到。我只需要调用它。谢谢!
    • 这当然是最有用的答案之一。我现在没有。
    【解决方案2】:

    你要找的是 RxJS toPromise() 函数。

    import { map } from 'rxjs/operators';
    
    public getDataSet(): Promise<any> {
      return this.get().pipe(
        map(data => new DataSet(data))  // <-- transform incoming data from subscription
      ).toPromise();
    }
    

    然后你可以等待这个函数。

    // in some component
    
    public async getDataSet() {
      this.dataSet = await this.someService.getDataSet();
    }
    

    但要注意 toPromise() 是来自 RxJS v7 的 deprecated(在撰写本文时为当前版本),并且会在 RxJS v8 中消失。

    【讨论】:

    • 这是反过来的吗? OP 希望返回一个 Observable,而不是 Promise。
    • @RobertoZvjerković:我再次回答了这个问题,但仍然不太明白。所以 OP 想要返回一个 observable 并在上面使用async/await
    • 我已经在使用toPromise(),但有所不同。您的示例中的问题是您没有检查 this.dataset 是否已经可用。您的解决方案会起作用,但 async/await 看起来要好得多。不过感谢您的提议!
    • @Tot:抱歉,我忽略了问题中的if 检查。看起来您正在尝试为可观察的值提供缓存机制。您可以将 shareReplay(1) 与缓冲区 1 一起使用,如 Poul Kruijt 在他的回答中所示。
    【解决方案3】:

    您还可以执行以下操作,因为不赞成将 promise 与 observable 混合使用 :):

    public getDataSet() : Observable<any> {
      return this.dataset ? of(this.dataset) : this.get().pipe(
        map((dataset) => {
          this.dataset = new DataSet(data);
          return this.dataset;
        })
      );
    }
    

    但是,如果第一个请求尚未完成,上述解决方案可能会触发双重请求。


    感觉就像你试图让它缓存值。在这种情况下,您可以使用 shareReplay() 运算符执行以下操作。这样,get 请求在第一个subscribe 处触发,之后返回响应而不触发请求。它为您省去了使用中介属性的麻烦:

    private dataSet$ = this.get().pipe(
      map((data) => new DataSet(data)),
      shareReplay(1)
    );
    
    public getDataSet() : Observable<any> {
      return this.dataset$;
    }
    

    【讨论】:

    • 我认为您的解决方案最适合我的实际情况。但是,它并不能完全解决最初的问题(将async/await 与 RxJS 的from() 一起使用)。我会接受另一个答案,但我希望你的答案能得到最多的支持!
    • @Tot 是的,这是典型的XY Problem
    【解决方案4】:

    为什么不单独定义您的可观察对象,并在需要时返回它? shareReplay 充当数据集的缓存,因此您根本不需要声明 this.dataset

    dataset$ = get().pipe(
      map(data => new DataSet(data)),
      shareReplay(1)
    );
    
    public getDataSet() : Observable<any> {
      return this.dataset$.pipe(
        take(1)
      );
    }
    

    【讨论】:

    • 与上面的答案相同(来自@Poul_Kruijt)......哦,事实上更好,因为它使用了 DataSet 类型!虽然有时我想使用await ...toPromise(),但这不会使shareReplay(1) 运算符受益。我刚刚测试过它,当然它完成了 observable。有时 observables 非常实用和流畅,有时与 async/await 相比是一团糟。我得看看什么是最好的。
    • async/await 是 promise 的语法糖。由于它在语言规范中得到支持,它会变得更好,因为一些复杂性被抽象到语言本身中。话虽如此,我会避免将ObservablesPromises 混合使用,除非在使用其中一个的库之间的边界处。
    猜你喜欢
    • 2021-05-24
    • 2020-12-01
    • 2023-03-23
    • 1970-01-01
    • 2016-12-25
    • 2018-02-19
    • 2021-04-11
    • 2021-10-27
    • 2018-02-22
    相关资源
    最近更新 更多