RxJS中的同步性

时间:2014-01-23 11:49:52

标签: javascript asynchronous system.reactive reactive-extensions-js rxjs

我希望以下代码可以异步运行:

var range = Rx.Observable.range(0, 3000000);

range.subscribe(
  function(x) {},
  function(err) {},
  function() {
    console.log('Completed');
});

console.log('Hello World');

但事实并非如此。需要一段时间才能完成大范围的数字,只有在完成后才能恢复执行,您可以尝试代码here

我很困惑何时期望RxJS同步或异步运行。它取决于使用的方法吗?我之前的想法是,一旦我们进入Observables / Observer土地,其中的所有内容都是异步运行的,类似于承诺的工作方式。

1 个答案:

答案 0 :(得分:21)

RxJ遵循与Rx.Net相同的规则。默认情况下,每个可观察操作符使用执行其工作所需的最小异步数量。在这种情况下,Range可以同步运行数字,因此its documentation会告诉您默认使用Rx.Scheduler.currentThread

如果您想引入比操作所需的更多异步性,您需要告诉它使用不同的Scheduler

要获得您期望的行为,您需要使用Rx.Scheduler.timeout。实质上,这将使其通过setTimeout安排每次迭代。 (实际上并非如此简单,调度程序将使用浏览器中可用的最快方法来安排延期工作)。

var range = Rx.Observable.range(0, 3000000, Rx.Scheduler.timeout);

updated jsFiddle

请注意,通过setTimeout迭代300万个数字将几乎永远。所以也许我们想要分批处理它们。所以在这里我们将利用Range的默认行为来同步运行,然后批量处理并使用observeOn通过我们的超时调度程序运行批处理:

var range = Rx.Observable
    .range(0, 3000000)
    .bufferWithCount(1000)
    .observeOn(Rx.Scheduler.timeout) // run each buffer via setTimeout
    .select(function (buffer, i) {
       console.log("processing buffer", i);
       return Rx.Observable.fromArray(buffer);
     })
    .concatAll(); // concat the buffers together

jsFiddle请注意,在range完成所有3,000,000个值并且bufferWithCount生成3,000个数组时,会有一个延迟。对于真正的生产代码而言,这类内容并不常见,因为您的数据源不像Observable.range那样简单。

在这方面,FYI承诺没有任何不同。如果您对已完成的承诺调用then,则then函数可能会同步运行。所有Promises和Observable实际上都提供了一个接口,通过该接口,您可以提供在满足条件时保证运行的回调,条件是否已满足或稍后是否满足。然后,RxJs提供了许多机制来强制某些东西以异步方式运行,如果你真的想要那样的话。以及介绍具体时间的方法。