在使用测试调度程序时,如何链接RxJS承诺?

时间:2017-06-16 07:46:47

标签: javascript promise rxjs

在使用具有延迟传递的Observable的代码中,我可以使用TestScheduler在虚拟时间内使传递无实际延迟。但是,似乎如果我将这样的Observable转换为Promise并尝试将它们链接在一起,那么只有第一个Promise才能得到解决。如何在不等待实时解决的情况下测试使用此类延迟的系统?

请参阅下面的剪辑:请注意更改' sched'到'异步'并评论出' flush'除了缓慢之外,line会使它按预期运行。如何在没有延迟的情况下运行这一系列承诺?



var sched = new Rx.TestScheduler();
//var sched = Rx.Scheduler.async;

Rx.Observable.timer (100, sched).toPromise ().then (
  () => $("#test").text("100")).then (
  () => Rx.Observable.timer (100, sched).toPromise ()).then (
  () => $("#test").text("200")).then (
  () => Rx.Observable.timer (100, sched).toPromise ()).then (
  () => $("#test").text("300")).then (
  () => Rx.Observable.timer (100, sched).toPromise ()).then (
  () => $("#test").text("400"));

sched.flush ();

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://unpkg.com/@reactivex/rxjs@5.4.0/dist/global/Rx.min.js"></script>

<div id="test"></div>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

问题是在解析Promise之后,直到控制流返回到顶层之后才会调用其回调。这意味着在调用sched.flush()期间解决第一个承诺后,新的回调会排队,但直到sched.flush()完成后才会发生这种情况。但是我们仍然需要sched.flush()再次运行以使第二个Observable完成,依此类推。

原则上,这意味着我们只需要异步重新调用sched.flush()几次,以便完成所有可观察对象。我们可以通过创建一个单独的Promise链来执行此操作,该链在每个回调上刷新调度程序。唯一的问题是,目前还不清楚如何判断Observable是否已经准备就绪,因为没有明确定义的无关Promise回调的执行顺序。

我的解决方案只是创建一个Promise链,它执行一个刷新调度程序的回调函数,然后递归重新插入,直到它发现它不再需要这样做。这依赖于原始的回调产生某种可以测试的副作用(但是由于要求单元测试,这似乎是合理的 - 如果没有这样的效果,它就不可测试在第一种情况下)。在实际代码中,它还需要在检测到代码结束后执行任何断言,测试拆解等。我还安排它以便它具有有限的迭代次数,因此如果测试的代码以某种方式失败,它不会无限地递归。

&#13;
&#13;
var sched = new Rx.TestScheduler();
var finished = false;
//var sched = Rx.Scheduler.async;

Rx.Observable.timer (100, sched).toPromise ().then (
  () => $("#test").text("100")).then (
  () => Rx.Observable.timer (100, sched).toPromise ()).then (
  () => $("#test").text("200")).then (
  () => Rx.Observable.timer (100, sched).toPromise ()).then (
  () => $("#test").text("300")).then (
  () => Rx.Observable.timer (100, sched).toPromise ()).then (
  () => $("#test").text("400")).then (
  () => finished = true );

let f = n => { 
   sched.flush (); 
   if (n > 0 && !finished) {
       return Promise.resolve(n - 1).then(f); 
   } 
   else {
       $("#test").append (" [" + n + " iterations left]");
   }
}
Promise.resolve(100).then(f);
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://unpkg.com/@reactivex/rxjs@5.4.0/dist/global/Rx.min.js"></script>

<div id="test"></div>
&#13;
&#13;
&#13;