简体   繁体   English

RxJS Observable - 在使用下一个发射值之前等待异步方法完成

[英]RxJS Observable - Wait for async method to complete before using next emitted value

I'm applying an async method to each value emitted by an observalbe.我正在对 observalbe 发出的每个值应用异步方法。 I would like this async method to be applied to the next emitted value only once the async method completed for the previous value.我希望仅在异步方法为前一个值完成后才将此异步方法应用于下一个发出的值。

Here is a short example:这是一个简短的例子:

import { of } from "rxjs";

const timeout = (ms) => {
    return new Promise(resolve => setTimeout(resolve, ms));
};

of(1, 2, 3).subscribe(async (val) => {
  console.log(`starting to use ${val}`);
  await timeout(1000);
  console.log(`done using  ${val}`);
});

timeout is updating my state and fetching data from a server timeout 正在更新我的 state 并从服务器获取数据
Output: Output:

// starting to use 1
// starting to use 2
// starting to use 3
(wait 1 sec)
// done using 1
// done using 2
// done using 3

What I would lie to get is:我会撒谎得到的是:

// starting to use 1
(wait 1 sec)
// done using 1
// starting to use 2
(wait 1 sec)
// done using 2
// starting to use 3
(wait 1 sec)
// done using 3

You can simply use concatMap :您可以简单地使用concatMap

of(1, 2, 3).pipe(
   concatMap(val => timeout(1000))
);

concatMap will receive the 3 emitted values and will "work" on them one at a time, waiting for the result of each promise before moving on to the next one. concatMap将接收 3 个发出的值,并一次对它们“工作”,等待每个 promise 的结果,然后再继续下一个。

Here's a working StackBlitz demo.这是一个有效的StackBlitz演示。

With adding an await before the timeout call like so: await timeout(1000) this will at least bring your code inside the async ()=>{} in the right order.在超时调用之前添加await ,如下所示: await timeout(1000)这至少会将您的代码以正确的顺序放入async ()=>{}中。 However the function is started in the moment a new event occurs in the observable.然而,function 在 observable 中发生新事件时启动。 This lets you see the three starting log at the beginning.这使您可以在开头看到三个启动日志。

If you want your observable to emit one value per second you may consider using interval or some debounce mechanims instead of of()如果您希望您的 observable 每秒发出一个值,您可以考虑使用interval或一些去抖动机制而不是of()

You can use from to convert a promise to an Observable.您可以使用from将 promise 转换为 Observable。 With that you have full control of your observables, and you get to use all the nice things which rxjs provided (all other methods and operators like pipe, switchMap, etc).这样你就可以完全控制你的 observables,并且你可以使用 rxjs 提供的所有好东西(所有其他方法和运算符,如 pipe、switchMap 等)。

import { of, from } from 'rxjs';

of(1, 2, 3)
    .pipe(
        switchMap((val) => {
            console.log(`starting to use ${val}`);
            return from(timeout(1000))
        })
    )
    .subscribe(finalValue => {
        console.log(`done using  ${val}`);
    })

From the docs (no pun intended):来自文档(没有双关语):

Creates an Observable from an Array, an array-like object, a Promise, an iterable object, or an Observable-like object.从一个数组创建一个 Observable,一个类似数组的 object,一个 Promise,一个可迭代的 object,或者一个类似 Observable 的 objectA8CFDE891111

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM