Node.js:如果不阻塞事件循环,你将如何重新创建'setTimeout'函数?

时间:2012-01-21 00:03:33

标签: javascript node.js

我已经做了很多搜索,试图找出如何在Node.js中创建非阻塞代码。不幸的是,我发现的每个例子都基于一个函数,最终它已经内置了一个回调函数。所以我想用回调创建自己的函数,但由于某种原因它阻止了事件循环。这并没有阻止事件循环:

function foo(response){
    setTimeout(function(){
        response.writeHead(200, {"Content-Type": "text/plain"});
        response.write("bar");
        response.end();
    }, 7000);
}

但是这样做了:

function foo(response){
    function wait(callback, delay){
            var startTime = new Date().getTime();
        while (new Date().getTime() < startTime + delay);
        callback();
    }
    wait(function(){
        response.writeHead(200, {"Content-Type": "text/plain"});
        response.write("bar");
        response.end();
    }, 7000);
}

我错过了非阻塞代码的哪些基本方面?

修改

我重新创建setTimeout的目标更多的是我认为我会尝试的心理练习,所以我可以更好地理解偶数循环。现在我担心如果我有一些相当繁重的服务器端代码在JavaScript中进行一些原始处理,我不知道如何阻止它停止我的事件循环。

在阅读了你的答案并进一步思考之后,我认为一个更准确的问题可能就是这样:如果我在我的服务器上使用JavaScript进行大量处理,我该如何阻止它中断事件循环?

这是我第一次在这里发帖,所以我不知道我会得到什么样的回应。到目前为止,这太棒了。谢谢,伙计们。

编辑2: 嘿,再次感谢大家的建议。我最终尝试了process.nextTick,就像Raynos建议的那样......它有效!我设法用回调创建自己的非阻塞计时器。代码并不完美,但对于那些好奇的人来说,这就是它的外观:

var timer = {};

function delay(callback, length){
    if(!timer.startTime){
        timer.startTime = new Date().getTime();
        timer.callback = callback;
        timer.length = length;
    }
    if(new Date().getTime() < timer.startTime + timer.length){
        process.nextTick(delay);
    } else {
        timer.callback();
        timer = {};
    }
}

function list(response){
    delay(function(){
        console.log("callback");
        exec("dir", function (error, stdout, stderr) {
            response.writeHead(200, {"Content-Type": "text/plain"});
            response.write(stdout);
            response.end();
        });
    }, 7000);
}

并不打算使用此代码。但是学习如何做到这一点的过程肯定有助于我理解一些关于非阻塞的关键概念。

对于那些仍然对非阻塞感到好奇的人,你应该看看Raynos' article.

4 个答案:

答案 0 :(得分:3)

为了不阻止事件循环,您的代码必须最终返回到事件循环并允许它继续处理。除非您的代码实际返回到事件循环,否则它不会使下一条消息出列并处理它。此代码不会在给定时间段内退出,因此永远不会将控制权返回给事件循环。

答案 1 :(得分:0)

你有大部分正确的想法 - 你想编写一个快速执行的函数,然后将控制权返回给主事件循环。而不是函数本身闲置等待(在你的情况下通过字面上坐在while循环和休眠),它注册一个回调 - 通常使用setTimeout - 然后返回。然后,当调用超时时,它会唤醒并执行它需要的任何功能。

function foo(response){
    function wait(callback, delay){
            var startTime = new Date().getTime();
        // this will block the event loop until this condition is true
        while (new Date().getTime() < startTime + delay);
        //then the callback is called
        callback();
        //then it goes back to the event loop
    }
    wait(function(){
        response.writeHead(200, {"Content-Type": "text/plain"});
        response.write("bar");
        response.end();
    }, 7000);
}

答案 2 :(得分:0)

也许你想要一个包装?

function wait(callback, delay){
    setTimeout(callback, delay);
}

答案 3 :(得分:0)

当你调用一个函数时,你不会开始一个新的线程。因此,在wait函数中运行while循环将阻止执行。