如何使用RxJS将一系列Promise转换为Rx.Observable?

时间:2016-10-25 11:20:38

标签: javascript typescript async-await rxjs

我尝试使用RxJS从Promise链中创建Rx.Observable。与this question的区别在于我的Promise数量未知,而且每个Promise都取决于前一个Promise的结果。

基本上我有一系列页面,与"下一页"链接。

我想要的功能是:

  • 等待承诺<>
  • 提供结果(fire observer.onNext())
  • 检查是否有下一页链接
  • 创建下一个Promise<>用那个链接
  • 重复,直到有剩余页面

我尝试了以下内容:

private getPages<T>(firstPromise: PromiseLike<IODataCollectionResult<T>>): Rx.Observable<T> {

    let observable = Rx.Observable.create<T>(async obs => {
        let page = await firstPromise;
        page.value.forEach(v => obs.onNext(v));

        while (page['@odata.nextLink']) {
            let nextPageUrl = <string>page['@odata.nextLink'];
            let nextPagePromise = <PromiseLike<IODataCollectionResult<T>>>this.resource(nextPageUrl).get().$promise;
            page = await nextPagePromise;
            page.value.forEach(v => obs.onNext(v));
        }

        obs.onCompleted();
    });

    return observable;
}

IODataCollectionResult是一个OData结果,其中&#39; @ odata.nextLink&#39;是下一页的网址,而.value是一个值数组)

问题我无法用TypeScript编译它,它给了我一个错误:

  

类型的参数&#39;(obs:Observer)=&gt;诺&#39;不能分配给&#39;(观察者:观察者)=&gt;类型的参数。无效|功能| IDisposable的&#39;

这是有道理的,因为异步函数返回Promise<void>,而不是void

这是否意味着我不能对Rx.Observable.create()使用async / await?如何将一系列Promise链接到一个Observable?

2 个答案:

答案 0 :(得分:1)

你可以将async function包裹在使结果无效的东西中:

function toVoid<A>(fn: A => Any): A => Void {
    return x => void fn(x)
}

(原谅我对TypeScript缺乏了解,但我希望你能猜出它应该做什么)

有了这个,你应该可以打电话了

let observable = Rx.Observable.create<T>(toVoid(async obs => {
    …
}));

但也许你不应该这样做。不要丢弃承诺,而是使用它来附加相应的错误处理程序:

let observable = Rx.Observable.create<T>(obs => {
    (async () => {
        …
    }()).catch(err => {
        obs.onError(err);
    });
});

答案 1 :(得分:0)

问题是使用.then()+递归解决的,没有async / await:

private getPages<T>(initialPromise: PromiseLike<IODataCollectionResult<T>>): Rx.Observable<T> {
    return Rx.Observable.create<T>(obs => {
        const getPage = (promise: PromiseLike<IODataCollectionResult<T>>) => {
            promise.then(page => {
                page.value.forEach(v => obs.onNext(v));
                if (page['@odata.nextLink']) {
                    let nextPageUrl = <string>page['@odata.nextLink'];
                    let nextPagePromise = <PromiseLike<IODataCollectionResult<T>>>this.resource(nextPageUrl).get().$promise;
                    getPage(nextPagePromise);
                }
                else {
                    obs.onCompleted();
                }
            });
        }
        getPage(initialPromise);
    });
}