“收益”Node.js中的计算

时间:2015-05-26 09:51:01

标签: javascript node.js control-flow

我在我的节点应用程序中有一个更大的计算(~0.5秒),我想在不使用webworker的情况下使其成为非阻塞。 (我认为网络工作者在这种情况下会有点矫枉过正) 有没有办法强制返回主循环,以便让节点有机会处理另一个请求?

1 个答案:

答案 0 :(得分:6)

听起来你说你想在主线程上以一口大小的块进行计算,而不是将它旋转到自己的线程(例如,使用webworker-threads或子进程或者等)。

我可以想到三个选择:

  1. ES6发电机功能。

  2. 一个返回状态的函数,让你再次使用状态对象调用它(这基本上就是ES6生成器的功能,但是它们为你提供了更好的语法)。

  3. 使用nextTick继续独立运行的功能,而无需控制其运行方式。

  4. 第三个选项为调用代码提供最少的控制权;第一个和第三个可能最容易实现。

    ES6发电机功能

    您可以通过--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
    })();