我开始学习一些node.js
和asynchronus事件杂耍并遇到问题。
说我有n
个不同的node.js流可读,我可以得到。每个都会生成我要存储的data
个事件。当所有流完成后,我想在控制台中记录所有结果。到目前为止我所拥有的:
outputs = [];
//Construct an array in which the outputs will wait for the streams to finish:
for(var i = 0; i < n; i++){
outputs.push('');
}
ended = 0;
for(var i = 0; i < n; i++){
var ithReadable = getReadableStreamSomehow(i); // produces the i-th readable stream.
ithReadable.on('data', function(chunk){
outputs[i] += chunk;
});
ithReadable.on('end', function(chunk){
ended++;
if (ended == n){
console.log(outputs);
}
});
}
此代码背后的理念是:
对于从i
到0
的每个n-1
,代码开始侦听第i个可读流,生成监听流的2n
函数。当流生成data
事件时,我想将其存储到i
- 输出中。当所有流完成后,我打印出他们的结果。
我提供的代码不起作用。据我了解,问题是当i
从1更改为2时,编写为侦听1
流的函数现在要写入outputs[2]
而不是{ {1}},让上帝变得糟透了。
我的问题是:
我知道我想做的事情最好通过outputs[1]
来实现。然而,这是关于我学习异步编程的原理并希望以这种方式推进。我怎样才能避免像全局变量(pipe
)弄乱我的回调函数的情况?有没有办法做我想做的事情(但实际上是在工作)?
谢谢。
答案 0 :(得分:2)
您需要在自己的作用域中声明一个不会被for循环修改的新变量。我建议关闭。
观察这两个异步代码块之间的区别,并尝试在Chrome控制台中运行它们:
for(var i = 0; i < 10; i++){
setTimeout(function(){ //This function is asynchronous.
console.log(i);
}, 1000);
}
第2版:
for(var i = 0; i < 10; i++){
// This anonymous function executes immediately, once per loop, and is not asynchronous
(function(){
var k = i; // once k is instantiated it will not be modified again.
setTimeout(function(){
console.log(k);
}, 1000);
})();
}
每个请求,这个高效版本不会在循环中创建任意数量的函数。如果setTimeout在Node中接受了第三个参数(传递给回调的参数),我们还可以在循环运行之前创建setATimeout
中使用的匿名函数。
function setATimeout(i){
// i was passed by value since it is a primitive, so no scope problems.
setTimeout(function(){
console.log(i);
}, 1000);
}
for(var i = 0; i < 10; i++){
setATimeout(i);
}
答案 1 :(得分:0)
我有个主意。 Javascript的函数构造函数允许您将函数体定义为字符串:
ithReadable.on('data', new Function("chunk", "outputs[" + i + "] += chunk;");
文档:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
答案 2 :(得分:0)
请尝试以下代码。
在javascript中使用up-closure-scope变量时应该小心。
Java要求闭包变量为最终值。
与Java不同,Javascript允许修改闭包变量。
在这种情况下,您应该在某个对象中传递值而不是闭包变量。
幸运的是,node.js在回调事件处理时传递“this”。
ithReadable.idx = i;
ithReadable.on('data', function(chunk){
outputs[this.idx] += chunk;
});
答案 3 :(得分:0)
跟进@AlexMA和IIFE版本
for(var i = 0; i < 10; i++){
// This anonymous function executes immediately, once per loop, and is not asynchronous
(function(k){
//k is local it will not be modified.
setTimeout(function(){
console.log(k);
}, 1000);
})(i); // pass i to anonymous function
}