RxJS与Math.random()的搭配不太好

时间:2017-03-07 18:20:40

标签: javascript rxjs rxjs5

我正在尝试学习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会更新。

1 个答案:

答案 0 :(得分:2)

这是因为您每次订阅时都会使用新的源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