我一直在与RxJS一起探索边缘,并遇到了一些意外的事情。
考虑以下代码:
of(1)
.pipe(expand(x => of(x + 1)))
.subscribe(
x => console.log(x),
err => console.log(err),
() => console.log('complete'));
当在节点中运行时,我希望它会产生一个无限的数字列表,每个数字都增加1,当它超过JavaScript中的最大数量时最终会出错,或者我将使用Ctrl-C终止它(在Windows上) 。我没想到的是,在记录了少于1000个数字之后,它将停止并且没有错误。
我得到的是写入控制台的数字1-783。
然后它停止了。
每次。
我运行它。它停在783(不是一个特殊数字-256、1024等)。它不会记录错误或“完成”。它只是停止。
我希望它可以“永远”运行,抛出错误或至少退出“完成”状态。但是它只是停止并返回命令行。
我进行了一些挖掘,认为可能与可选的并发参数有关,根据docs for expand,该参数默认为Number.POSITIVE_INFINITY
。
但是,如果我为该参数明确指定值,则会得到同样奇怪的结果-即并发1导致的值(一致地〜860)比并发值1,000,000(回到783)多,超过100( 〜850)和超过200(〜840)。似乎大多数并发值为1的情况下发出,然后随着并发程度的增加缓慢地降低到783个值的低点。就是说,我不知道实际上是并发影响了这一点,尽管它似乎确实相关。
我快速浏览了expand的源代码,但没有发现任何可以解释这一点的东西。
这不是我将要在生产中运行的代码,但它激起了我的好奇心。有谁有什么想法可以解释这一点?
RxJS 6.3.2
节点8.9.4
谢谢
TTE
答案 0 :(得分:3)
这是预期的行为。我不确定为什么您没有从node.js收到任何错误消息,但实际上是这样的:
RangeError: Maximum call stack size exceeded
at SafeSubscriber.__tryOrUnsub (/Users/ojkwon/github/goj/node_modules/rxjs/internal/Subscriber.js:212:18)
...
简而言之,它正在堆栈溢出。
当您调用expand
时,您将返回通过of
创建的observable,并通过expand运算符递归。 Rx v5及更高版本的调度行为默认情况下为not scheduling anything
-意味着,您创建了同步可观察的对象,并再次创建了同步堆栈,最终崩溃了。
您可以通过使用异步源或给定值进行无限扩展来显式异步地进行调度:即,如果您安排通过异步调度程序中的expand
观察到返回的值
const { of, asyncScheduler } = require('rxjs');
const { expand } = require('rxjs/operators');
of(1)
.pipe(expand(x => of(x + 1, asyncScheduler)))
.subscribe(
x => console.log(x),
err => console.log(err),
() => console.log('complete'));
那么您可以观察到操作员不会停止。