RxJS:即使外部可观察对象没有预订,延迟的内部可观察对象仍会运行

时间:2018-08-16 16:06:24

标签: rxjs

我刚刚意识到,即使外部可观察对象没有订阅,内部可观察对象(例如在mergeMap或switchMap运算符中定义的那些对象)也不会“停止”。

举个更好的例子,让我们展示一些代码:

const {
  Subject,
  of: obsOf,
  concat: obsConcat,
  defer,
} = require("rxjs");
const {
  finalize,
  mergeMap,
  tap,
  takeUntil,
} = require("rxjs/operators");

const subject = new Subject();

obsOf(null).pipe(
  mergeMap(() =>
    obsConcat(
      defer(() => {
        console.log("side-effect 1");
        return obsOf(1);
      }),
      defer(() => {
        console.log("side-effect 2");
        return obsOf(2);
      }),
      defer(() => {
        console.log("side-effect 3");
        return obsOf(3);
      })
    )
  ),
  finalize(() => {
    console.log("finalized");
  })
)
.pipe(
  takeUntil(subject),
  tap((i) => {
    if (i === 2) {
      subject.next();
    }
  })
).subscribe(
  (i) => { console.log("next", i); },
  (e) => { console.log("error", e); },
  () => { console.log("complete"); },
);

// Ouput:
// > side-effect 1
// > next 1
// > side-effect 2
// > complete
// > finalized
// > side-effect 3

记录了side-effect 3行的事实很奇怪,因为外部可观察到的已经叫finalize

由于所有这些副作用都在defer中,因此可以在取消订阅后完全避免它们。从我的角度来看,这些副作用根本没有任何价值。

是否知道为什么RxJS仍执行那些代码?

1 个答案:

答案 0 :(得分:0)

不幸的是,这是设计使然(从RxJS 6开始)-concat将缓冲可观察对象,并且即使您取消订阅也将订阅每个缓冲的对象(如果订阅为closed,它将立即订阅退订)。

您必须防止可观察对象被缓冲...

obsOf(null).pipe(
  mergeMap(() => obsOf(
    defer(() => {
      console.log("side-effect 1");
      return obsOf(1);
    }),
    defer(() => {
      console.log("side-effect 2");
      return obsOf(2);
    }),
    defer(() => {
      console.log("side-effect 3");
      return obsOf(3);
    })
  )),
  concatAll(),
  finalize(() => {
    console.log("finalized");
  }),
  takeUntil(subject),
  tap((i) => {
    if (i === 2) {
      subject.next();
    }
  })
).subscribe(
  (i) => { console.log("next", i); },
  (e) => { console.log("error", e); },
  () => { console.log("complete"); },
);

一个人可能认为上面的代码有效,但是直到您延迟了其中一个可观察对象。将obsOf(1)替换为timer(100).pipe(mapTo(1));,其行为完全相同。

唯一的解决方法是确保您不缓冲任何内容(意味着不使用concat*运算符)或以其他方式限制可观察的生产(使用单独的Subject并手动控制生产)。