在javascript中编写非阻塞的for循环最干净的方法是什么?
What's the cleanest way to write a non-blocking for loop in javascript?
所以,我一直在思考一个脑筋急转弯-如果我有一个大的对象,我出于某种原因不得不在node js中迭代,并且不想在我这样做的时候阻止事件循环呢?
这是一个我想不到的例子,我相信它可以更简洁:
var forin = function(obj,callback){
var keys = Object.keys(obj),
index = 0,
interval = setInterval(function(){
if(index < keys.length){
callback(keys[index],obj[keys[index]],obj);
} else {
clearInterval(interval);
}
index ++;
},0);
}
虽然我确定还有其他原因导致它很混乱,但这将比常规的for循环执行得慢,因为setInterval 0实际上并不是每0毫秒执行一次,但我不确定如何使用更快的process.nextTick.
在我的测试中,我发现这个例子需要7毫秒来运行,而不是本机for循环(使用hasOwnProperty()检查,记录相同的信息),它需要4毫秒
那么,使用node.js编写相同代码的最干净/最快的方法是什么?自提问以来,process.nextTick
的行为发生了变化。前面的答案也没有按照函数的清洁度和效率来回答问题。
// in node 0.9.0, process.nextTick fired before IO events, but setImmediate did
// not yet exist. before 0.9.0, process.nextTick between IO events, and after
// 0.9.0 it fired before IO events. if setImmediate and process.nextTick are
// both missing fall back to the tick shim.
var tick =
(root.process && process.versions && process.versions.node === '0.9.0') ?
tickShim :
(root.setImmediate || (root.process && process.nextTick) || tickShim);
function tickShim(fn) {setTimeout(fn, 1);}
// executes the iter function for the first object key immediately, can be
// tweaked to instead defer immediately
function asyncForEach(object, iter) {
var keys = Object.keys(object), offset = 0;
(function next() {
// invoke the iterator function
iter.call(object, keys[offset], object[keys[offset]], object);
if (++offset < keys.length) {
tick(next);
}
})();
}
请注意@alessioalex关于Kue和适当的作业队列的评论。
请参阅:share-time,这是我编写的一个模块,用于实现与原始问题类似的目的。
这里有很多话要说。
- 例如,如果你有一个web应用程序,你不会想要在该应用程序的进程中做"繁重的工作"。即使你的算法是有效的,它仍然很可能会减慢应用程序。
- 根据你想要达到的目标,你可能会使用以下方法之一:
A)将"for in"循环放在子进程中,并在主应用程序中获得结果,一旦它结束
b)如果您正在尝试实现延迟工作(例如发送电子邮件),您应该尝试https://github.com/LearnBoost/kue
c)使用Redis在主应用程序和"繁重"应用程序之间进行通信,创建一个类似kuis的程序。
对于这些方法,您也可以使用多个进程(用于并发)。
现在是一个示例代码的时间(它可能不是完美的,所以如果你有更好的建议请纠正我):
var forIn, obj;
// the "for in" loop
forIn = function(obj, callback){
var keys = Object.keys(obj);
(function iterate(keys) {
process.nextTick(function () {
callback(keys[0], obj[keys[0]]);
return ((keys = keys.slice(1)).length && iterate(keys));
});
})(keys);
};
// example usage of forIn
// console.log the key-val pair in the callback
function start_processing_the_big_object(my_object) {
forIn(my_object, function (key, val) { console.log("key: %s; val: %s;", key, val); });
}
// Let's simulate a big object here
// and call the function above once the object is created
obj = {};
(function test(obj, i) {
obj[i--] = "blah_blah_" + i;
if (!i) { start_processing_the_big_object(obj); }
return (i && process.nextTick(function() { test(obj, i); }));
})(obj, 30000);
而不是:
for (var i=0; i<len; i++) {
doSomething(i);
}
执行如下操作:
var i = 0, limit;
while (i < len) {
limit = (i+100);
if (limit > len)
limit = len;
process.nextTick(function(){
for (; i<limit; i++) {
doSomething(i);
}
});
}
}
这将运行100次循环,然后将控制返回给系统一会儿,然后从它离开的地方继续,直到它完成。
编辑:这里它适用于您的特定情况(以及它在作为参数传递的时间内执行的迭代次数):
var forin = function(obj, callback, numPerChunk){
var keys = Object.keys(obj);
var len = keys.length;
var i = 0, limit;
while (i < len) {
limit = i + numPerChunk;
if (limit > len)
limit = len;
process.nextTick(function(){
for (; i<limit; i++) {
callback(keys[i], obj[keys[i]], obj);
}
});
}
}
以下内容适用于[browser] JavaScript;它可能与node.js完全无关。
我知道的两个选项:
- 使用多个定时器处理队列。它们将交错,这将产生"更频繁地处理项目"的净效果(这也是窃取更多CPU的好方法;-),或者,
- 每个周期做更多的工作,无论是计数还是基于时间。
我不确定Web Workers是否适用/可用。
快乐编码。
相关文章:
- Array方法中的Javascript循环
- 如何在循环中使用jQuery.on()方法,而不覆盖我循环的对象
- 有没有一种方法可以在所有嵌套循环之后放置一个标签,以便在一步中将它们全部打断
- 特定循环(html元素)方法的优点和缺点
- MeteorJS使用流星调用和流星方法时的无限循环
- 使用click()方法是在创建一个无休止的循环
- 在 1 个方法中增加变量值会触发另一个方法的 for 循环,欢迎任何建议
- 循环遍历 DOM 元素时,是否有 for 循环的替代方法
- 在二维数组中搜索比嵌套循环更有效的方法
- 在Raphael JS中创建脉动(循环)背景的最简单方法
- 有没有任何方法可以使这个名称生成循环运行最短的秒数
- 对于许多类似的方法,使用for循环
- 可以't在对象数组上循环时调用公共方法
- Node.js:如何在一个循环中使用回调调用方法
- 在循环中创建函数的最有效替代方法
- JavaScript 将循环遍历数组的函数传递给使用 Switch 语句日期方法的函数
- RequireJS,循环依赖和导出“魔术”方法
- 每次迭代在 Foreach 循环中重复 PHP 睡眠方法
- 在nodejs中使用Q.js承诺进行循环的正确方法
- 在c#中创建一个自循环方法