RxJS 不能与 Math.random() 配合使用

RxJS does not play nice with Math.random()

我正在尝试学习 Rxjs,但我看到了一些我没有预料到的行为。下面列出了 javascript 有问题的代码

function updateText(css_link, observable){
  observable.subscribe(x => {
    const container = document.querySelector(css_link);
    container.textContent = `${x}`;
  });
}

function log(observable) {
  observable.subscribe(i => {
    console.log(i);
  });
}

let source = Rx.Observable.timer(0, 1000)
  .map(() => {return {value: Math.random()}});

let double = source
  .map(x => {return {value: x.value * 2}});

let diff = source
  .pairwise()
  .map(a => JSON.stringify(a));

updateText("#source", source.map(x => x.value));
updateText("#double", source.map(x => x.value));
updateText("#diff", diff);

事实证明,double 流的输出是新随机数的双精度值,而不是来自 source 的随机数。当查看 diff 的输出时,我再次感觉到随机数是在 sourcedoublediff 中独立生成的。

我正在学习 Rxjs,我可能漏掉了一点。我认为这些流是不可变的,但它们确实相互依赖。

您可以在 jsbin 上找到此代码的一个版本,其中一些 html 正在更新。

这是因为每次您订阅时,您都在创建一个带有新源 Observable 的新链。这意味着 sourcedoublediff 他们每个人都有自己的计时器。

您可以通过每次创建新计时器时向控制台打印一条消息来证明这是真的:

let source = Rx.Observable.defer(() => {
  console.log('new source');
  return Rx.Observable.timer(0, 1000)
    .map(() => {return {value: Math.random()}});
});

现在您将在控制台中看到三个消息 "new source"

如果你想共享单个源 Observable,你可以使用多播,特别是 share() 运算符。

let source = Rx.Observable.defer(() => {
  console.log('new source');
  return Rx.Observable.timer(0, 1000)
    .map(() => {return {value: Math.random()}});
}).share();

现在您在控制台中只会看到一个 "new source",它应该会如您所愿地工作。

因此您的来源可能如下所示:

let source = Rx.Observable.timer(0, 1000)
  .map(() => {return {value: Math.random()}})
  .share();

您更新的演示:https://jsbin.com/guyigox/3/edit?js,console,output