在经常使用节点之后,我不得不习惯以非阻塞的方式编写代码,但是我能做到这一点的主要方法是使用本身异步的函数。例如:stat(f,callback)
或forEach(array, callback)
他们自动接受你给出的任何回调,我认为它是主要的执行高速公路,并在被叫后立即返回。
我想知道的是:如何告诉ECMA引擎以异步方式执行函数?
我的特定用例涉及在DOM子列表上迭代for循环以解析数千个元素;我的问题是每个其他元素都是一个我想跳过的文本节点。虽然我会使用forEach()
这不是最好的,但我只看到for(a,i=0;a=table[i];i=i+2){/*process 'a'*/}
能够以阻止为代价来纠正这个问题。什么是最好的行动方案?
奖金问题:在JS必须做大量工作的用例中,NodeJS的编码实践是否在客户端应用程序中占有一席之地?
答案 0 :(得分:3)
注意:Array.prototype.forEach
是同步的,而不是异步的。 JS标准(ECMAScript 5th edition)中定义的任何内容都不能是异步的,因为标准没有定义异步语义(Node.js和DOM都有)。
您可以使用setTimeout
(适用于浏览器和Node.js)或process.nextTick
(特定于Node.js):
for (...) {
doWorkAsync(...);
}
function doWorkAsync(...) {
setTimeout(doWorkSync.bind(null, ...), 0);
}
function doWorkSync(...) {
...
}
如果选择利用闭包,请谨慎使用自由变量,因为最终调用回调时变量可能会发生变异。
使用异步框架,例如Q by kriskowal(可在Node.js和现代浏览器中移植),您可以进行mapreduce风格的编程:
var Q = require('q'); // npm package 'q'
function getWorkloads() {
var workloads = [ ];
for (...) {
workloads.push(Q.fcall(doWorkSync.bind(null, ...)));
}
return workloads;
}
Q.all(getWorkloads()).then(function (results) {
// results array corresponds to
// the array returned by getWorkloads.
});
答案 1 :(得分:0)
我在同一条船上。我有点喜欢Node的异步函数,所以我写了这个async For和ForEach函数。它使用“setTimeout(Func,0);”特技。
这是图书馆:
var WilkesAsyncBurn = function()
{
var Now = function() {return (new Date());};
var CreateFutureDate = function(milliseconds)
{
var t = Now();
t.setTime(t.getTime() + milliseconds);
return t;
};
var For = function(start, end, eachCallback, finalCallback, msBurnTime)
{
var i = start;
var Each = function()
{
if(i==-1) {return;} //always does one last each with nothing to do
setTimeout(Each,0);
var burnTimeout = CreateFutureDate(msBurnTime);
while(Now() < burnTimeout)
{
if(i>=end) {i=-1; finalCallback(); return;}
eachCallback(i);
i++;
}
};
Each();
};
var ForEach = function(array, eachCallback, finalCallback, msBurnTime)
{
var i = 0;
var len = array.length;
var Each = function()
{
if(i==-1) {return;}
setTimeout(Each,0);
var burnTimeout = CreateFutureDate(msBurnTime);
while(Now() < burnTimeout)
{
if(i>=len) {i=-1; finalCallback(array); return;}
eachCallback(i, array[i]);
i++;
}
};
Each();
};
var pub = {};
pub.For = For; //eachCallback(index); finalCallback();
pub.ForEach = ForEach; //eachCallback(index,value); finalCallback(array);
WilkesAsyncBurn = pub;
};
示例用法:
WilkesAsyncBurn(); // Init the library
console.log("start");
var FuncEach = function(index)
{
if(index%10000==0)
{
console.log("index=" + index);
}
};
var FuncFinal = function()
{
console.log("done");
};
WilkesAsyncBurn.For(0,2000000,FuncEach,FuncFinal,50);
打印: 指数= 10000 指数= 20000 指数= 30000 等等 “完成”
更多研究如果感兴趣:
setTimeout和setInterval的最小开销时间约为2到10毫秒,因此,无论如何,激活数千或数百万个定时器的速度会很慢。所以基本上,如果你需要在不锁定浏览器的情况下执行数千或更多循环,你需要更像一个线程(喘气),并在一段时间内“烧”一些代码,而不是设置迭代次数。 / p>