简体   繁体   English

RxJS与Math.random()配合不好

[英]RxJS does not play nice with Math.random()

I am trying to learn Rxjs and I am seeing some behaviour that I did not expect. 我正在尝试学习Rxjs,并且看到了一些我没有想到的行为。 The javascript code in question is listed below 有问题的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);

It turns out that the output of the double stream are double values of new random numbers, not the random numbers that came from source . 结果表明double流的输出是新随机数的double值,而不是source的随机数。 When looking at the output of diff I again get the impression that the random numbers are generated independantly in source , double and diff . 当查看diff的输出时,我再次得到以下印象:随机数是分别在sourcedoublediff独立生成的。

I am learning Rxjs and I may be missing a point. 我正在学习Rxjs,可能遗漏了一点。 I thought that these streams are immutable but that they do depend on one another. 我认为这些流是不可变的,但是它们确实彼此依赖。

You can find a version of this code on jsbin with some html that is getting updated. 您可以在jsbin上找到此代码的版本, 带有一些正在更新的html。

This is because every time you subscribe you're creating a new chain with a new source Observable. 这是因为每次订阅时,您都在使用新的Observable源创建一个新链。 This means source , double and diff each one of them has its own timer. 这意味着sourcedoublediff每个都有自己的计时器。

You can see that this is true by printing a message to console every time you're creating a new timer: 您可以在每次创建新计时器时向控制台打印一条消息,以查看是否正确:

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

Now you'll see three messages "new source" in console. 现在,您将在控制台中看到三则消息"new source"

If you want to share a single source Observable you can use multicasting and in particular the share() operator. 如果要共享一个可观察的源,则可以使用多播,尤其是share()运算符。

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

Now you'll see only one "new source" in console and it should work as you expect. 现在,您将在控制台中仅看到一个"new source" ,它应该可以按预期工作。

So your source can look like this: 因此,您的来源可能如下所示:

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

Your updated demo: https://jsbin.com/guyigox/3/edit?js,console,output 您更新的演示: https : //jsbin.com/guyigox/3/edit?js,控制台,输出

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM