我在我的节点应用程序中有一个更大的计算(~0.5秒),我想在不使用webworker的情况下使其成为非阻塞。 (我认为网络工作者在这种情况下会有点矫枉过正) 有没有办法强制返回主循环,以便让节点有机会处理另一个请求?
答案 0 :(得分:6)
听起来你说你想在主线程上以一口大小的块进行计算,而不是将它旋转到自己的线程(例如,使用webworker-threads或子进程或者等)。
我可以想到三个选择:
ES6发电机功能。
一个返回状态的函数,让你再次使用状态对象调用它(这基本上就是ES6生成器的功能,但是它们为你提供了更好的语法)。
使用nextTick
继续独立运行的功能,而无需控制其运行方式。
第三个选项为调用代码提供最少的控制权;第一个和第三个可能最容易实现。
您可以通过--harmony_generators
标志在最新版本的NodeJS中使用ES6的生成器函数。生成器函数可以“回收”回调用代码,然后可以告诉他们在以后停止的地方进行调用。
以下是一个简单生成器的示例,该生成器计数到一个限制,每次调用时都会向计数添加一个:
function* counter(start, inc, max) {
while (start < max) {
yield start;
start += inc;
}
}
var x = counter(1, 1, 10);
console.log(x.next().value); // 1
console.log(x.next().value); // 2
console.log(x.next().value); // 3
请注意,不将计算转移到另一个线程,它只是让你做一点,做其他事情,然后回来再多做一点。< / p>
如果你不能使用生成器,你可以实现同样的东西,使一个对象的所有局部变量属性,让函数返回该对象,然后让它再次接受它作为参数:
function counter(start, inc, max) {
var state;
if (typeof start === "object") {
state = start;
if (!state.hasOwnProperty("value")) {
state.value = state.start;
} else if (state.value < state.max) {
state.value += state.inc;
} else {
state.done = true;
}
} else {
state = {
start: start,
inc: inc,
max: max,
done: false
};
}
return state;
}
var x = counter(1, 1, 10);
console.log(counter(x).value); // 1
console.log(counter(x).value); // 2
console.log(counter(x).value); // 3
您可以看到生成器如何简化事情。
这是一个函数的示例,该函数使用nextTick
以一口大小的作品执行其任务,并在完成时通知您:
function counter(start, inc, max, callback) {
go();
function go() {
var done = start >= max;
callback(start, done);
if (!done) {
++start;
process.nextTick(go);
}
}
}
counter(1, 1, 10, function(value, done) {
console.log(value);
});
现在,您不能在全局范围内使用生成器(您可能根本不想这样做),您必须在严格模式下的函数内执行此操作。 (即使是全球"use strict"
也不会这样做。)这是因为V8仍在使用其ES6功能......
当前版本节点的完整示例脚本(允许上述内容):
"use strict";
(function() {
function* counter(start, inc, max) {
while (start < max) {
yield start;
start += inc;
}
}
var x = counter(1, 1, 10);
console.log(x.next().value); // 1
console.log(x.next().value); // 2
console.log(x.next().value); // 3
})();