我是反应流中的新手,现在正试图理解它们。这个想法看起来非常简单明了,但在实践中我无法理解那里到底发生了什么。
现在我正在玩most.js,试图实现一个简单的调度程序。 scan方法似乎正是我所需要的。
我的代码:
var dispatch;
// expose method for pushing events to stream:
var events = require("most").create(add => dispatch = add);
// initialize stream, so callback in `create` above is actually called
events.drain();
events.observe(v => console.log("new event", v));
dispatch(1);
var scaner = events.scan(
(state, patch) => {
console.log("scaner", patch);
// update state here
return state;
},
{ foo: 0 }
);
scaner.observe(v => console.log("scaner state", v));
dispatch(2);
据我了解,第一个观察者应该被调用两次(每个事件一次),scaner回调和第二个观察者 - 每次一次(因为它们是在触发第一个事件后添加的)。
然而,在练习中,控制台会显示:
new event 1
new event 2
scaner state { foo: 0 }
无论我推进多少事件,都不会调用Scaner。
但是如果我删除第一个dispatch
调用(在创建scaner之前),一切都按照我的预期运行。
这是为什么?我正在阅读文档,阅读文章,但到目前为止还没有发现任何与此问题相似的内容。我的建议在哪里错了?
答案 0 :(得分:1)
最有可能的是,您已经从API
中学习了这样的示例most.from(['a', 'b', 'c', 'd'])
.scan(function(string, letter) {
return string + letter;
}, '')
.forEach(console.log.bind(console));
他们建议像这样一步一步地执行:
['a', 'b', 'c', 'd']
并将其值提供给流。scan()
转换。forEach()
消费。但这并非完全正确。这就是您的代码无法运行的原因。
在most.js源代码中,您可以看到第1340行:
exports.from = from;
function from(a) {
if(Array.isArray(a) || isArrayLike(a)) {
return fromArray(a);
}
...
因此from()
转发给某些fromArray()
。然后,fromArray()
(代码中的下方)正在创建新的Stream
:
...
function fromArray (a) {
return new Stream(new ArraySource(a));
}
...
如果您继续,则会从Stream
到sink.event(0, array[i]);
,其中0表示超时毫秒。代码中没有setTimeout
,但如果您进一步搜索代码.event = function
,您会发现许多其他代码可以揭示更多内容。特别是,在第4692行附近有Scheduler
delay()
和时间戳。
总结一下:上面例子中的数组在一段时间后异步进入流中,即使时间似乎是0毫秒。
这意味着您必须假设以某种方式首先构建流,然后使用。即使程序代码看起来不那样。但是,嘿,它始终是隐藏复杂性的目标:-)?
现在您可以使用自己的代码进行检查。这是一个基于你的片段的小提琴:
https://jsfiddle.net/aak18y0m/1/
查看小提琴中的dispatch()
来电。我用setTimeout()
包裹了它们:
setTimeout( function() { dispatch( 1 /* or 2 */); }, 0);
通过这样做,我强制它们也是异步调用,就像示例中的数组值实际上一样。
要运行小提琴,您需要打开浏览器调试器(查看控制台),然后按上面的运行按钮。控制台输出显示您的扫描仪现在被调用三次:
doc ready
(index):61 Most loaded: [object Object]
(index):82 scanner state Object {foo: 0}
(index):75 scanner! 1
(index):82 scanner state Object {foo: 0}
(index):75 scanner! 2
(index):82 scanner state Object {foo: 0}
首先是drain()
,然后是每个事件。
如果您在JavaScript能够构建整个流之后同步使用dispatch()
,并在最后添加它们,那么您也可以获得有效的结果(但幕后不一样)。只需取消注释// Alternative solution
之后的行,再次运行并观察结果。
答案 1 :(得分:0)
嗯,我的问题看起来并不像听起来那么笼统。它只是一个特定于lib的。
首先 - 从主题is not valid for most.js
开始。他们主张“采取陈述性而非强制性的方法”。
第二 - 我尝试了jdk_home/src.zip
lib,并且使用它来完成主题的代码。只是工作。更重要的是,Kefir.js
,is explicitly recommended for Kefir.js
中不支持相同的方法。
所以,问题在于特定的lib实现,而不是在我的脑海中。