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



在使用延迟交付的可观察量的代码中,我可以使用 TestScheduler 在虚拟时间内使交付在没有实际延迟的情况下发生。 但是,似乎如果我将这些可观察量转换为承诺并尝试将它们链接在一起,则只有第一个承诺才能解决。如何测试使用此类延迟的系统,而无需等待实时解决发生?

请参阅下面的截图:请注意,将"sched"更改为"异步"并注释掉"flush"行会导致其按预期运行,只是速度很慢。我怎样才能让这个承诺链在没有延迟的情况下运行?

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>

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

原则上,这意味着我们只需要异步重新调用sched.flush()几次,即可完成所有可观察量。 我们可以通过创建一个单独的 Promise 链来做到这一点,该链在每个回调时刷新调度程序。唯一的问题是,不清楚如何判断可观察量是否已经准备好了,因为对于不相关的 Promise 回调,没有明确定义的执行顺序。

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

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);
<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>

最新更新