RxJS-将fromEvent与switchMap一起使用时的奇怪行为

时间:2019-11-20 13:57:32

标签: typescript rxjs

我有一个事件发射器,它可以相当快地发射事件,有时在同一滴答中会发射多个事件。当我从此发射器创建可观察对象并使用switchMap时,我得到一些奇怪的行为,其中n的值进入switchMap,但只有1个出现。这是一些简化的代码:

const e = new EventEmitter();


const s = fromEvent<ConfigurationUpdatePayload>(
  e,
  'updated'
).pipe(
  take(4),
  map(() => Math.random() > 0.3 ? 1 : 2),
  tap(v => console.log('pre', v)), //pre log
  switchMap(async (i) => [
    await Promise.resolve((i + 1) === 2),
    i
  ] as const),
  tap(v => console.log('post', v)), //post log
  filter(([f,]) => f),
  map(([, p]) => p)
);


s.subscribe(v => console.log('result', v));

for (let i = 0; i < 4; i++) {
  e.emit('updated', 1);
  // await new Promise(res => setTimeout(res, 1000)); - if I uncomment this it works
}

在这里,我看到console.log('pre', v)被评估了4次,但console.log('post', v)仅被评估了一次。如果我在for循环中取消注释睡眠,那么一切都会按预期进行。

1 个答案:

答案 0 :(得分:1)

执行此操作时,这是一个同步发射,最终将发生一个事件,因为当发出源可观察对象时,switchMap将取消订阅/取消内部可观察对象,这在您的情况下是异步承诺。

它与以下情况类似

const e=new Subject();
e.pipe(switchMap(e=>timer(0).pipe(mapTo(e)))).subscribe(console.log)

for (let i = 0; i < 4; i++) {
  e.next('updated');
}

您最终只会得到一个“更新”。这里的解决方案之一是将switchMap替换为mergeMap

对于switchMap来说,这确实是一种预期行为,其中获得的发射量取决于源发射频率与内部可观察发射的频率。