Rxjs-在订阅函数内部等待

时间:2019-08-16 07:33:06

标签: rxjs

我如何在rxjs订阅函数中使用await,并在继续处理事件之前使promise得以解决?

这是一个codepen:https://codepen.io/parliament718/pen/YzKqMJB


let state = { end: 10 };


interval(500).pipe(
    switchMap(async (data) => {
       console.log('new quote', data);

       if(data >= state.end) {
          state.end = await getData();

         console.log('get new end', state);
       }
    })
  )
  .subscribe()


async function getData() {
  return await new Promise(resolve => {
    setTimeout(() => { resolve(state.end + 10) }, 600);
  });
}

输出为:

new quote 10
new quote 11
new end {end: 20}
new quote 12
new end {end: 30}
new quote 13

我需要的输出是:

new quote 10
new end {end: 20}
new quote 11
new quote 12
new quote 13

问题是在getData承诺解决之前会触发“ quote 11”,从而导致两次调用getData。

我认为switchMap应该可以处理这种情况。

1 个答案:

答案 0 :(得分:1)

部分问题是您试图在可观察的上下文中使用Promise。当外部可观察对象发出时,switchMap取消订阅任何内部可观察对象,但这仍然不是您想要的行为。您需要遵循以下原则:

interval(500).pipe(
  concatMap(data => { // concatMap places new emissions in a queue, waiting until each inner Observable completes before emitting the next one
    console.log('new quote', data);

    if(data >= state.end) {
      return from(getData()); // creates an Observable which completes when the Promise resolves
    } else {
      return of(false); // allows us to filter out states where getData isn't called
    }
  }),
  filter(newEnd => !!newEnd), // ignore anything where getData isn't called
  tap(newEnd => { // only if getData was called
    state.end = newEnd;
    console.log('get new end', state);
  })
).subscribe();

使用concatMap缓存下一个值,因此每个步骤中的比较仅在上一个完成后的 之后进行。