admin管理员组

文章数量:1323330

I've done a lot of searching to try and find out how to create non-blocking code in Node.js. Unfortunately, every example I've found is grounded to a function that, in the end, already has a built in callback. So I wanted to create my own function with a callback, but for some reason it blocks the event loop. This didn't block the event loop:

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

But this did :

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);
}

What fundamental aspect of non-blocking code am I missing?

Edit:

My goal to recreate setTimeout is more of a mental exercise I thought I'd try so I can understand the even loop a little better. Right now I'm worried that if I have some rather heavy server side code that's doing some raw processing in JavaScript, I won't know how to stop it from halting my event loop.

After reading your answers and thinking about this a bit further, I think a more accurate question would probably be this: If I'm doing heavy processing on my server with JavaScript, how do I stop that from interrupting the event loop?

It's my first time posting on here, so I didn't know what kind of response I was gonna get. So far, this is awesome. Thanks, guys.

Edit 2: Hey, so thanks again everyone for the advice. I ended up trying out process.nextTick like Raynos suggested... and it worked! I managed to create my own non-blocking timer with a callback. The code isn't perfect, but for those who are curious, this is how it looks:

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);
}

Not really intending to use this code. But the process of learning how to do this definitely helped me understand some key concepts about non-blocking.

And for those of you still curious about non-blocking, you should check out Raynos' article.

I've done a lot of searching to try and find out how to create non-blocking code in Node.js. Unfortunately, every example I've found is grounded to a function that, in the end, already has a built in callback. So I wanted to create my own function with a callback, but for some reason it blocks the event loop. This didn't block the event loop:

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

But this did :

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);
}

What fundamental aspect of non-blocking code am I missing?

Edit:

My goal to recreate setTimeout is more of a mental exercise I thought I'd try so I can understand the even loop a little better. Right now I'm worried that if I have some rather heavy server side code that's doing some raw processing in JavaScript, I won't know how to stop it from halting my event loop.

After reading your answers and thinking about this a bit further, I think a more accurate question would probably be this: If I'm doing heavy processing on my server with JavaScript, how do I stop that from interrupting the event loop?

It's my first time posting on here, so I didn't know what kind of response I was gonna get. So far, this is awesome. Thanks, guys.

Edit 2: Hey, so thanks again everyone for the advice. I ended up trying out process.nextTick like Raynos suggested... and it worked! I managed to create my own non-blocking timer with a callback. The code isn't perfect, but for those who are curious, this is how it looks:

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);
}

Not really intending to use this code. But the process of learning how to do this definitely helped me understand some key concepts about non-blocking.

And for those of you still curious about non-blocking, you should check out Raynos' article.

Share edited Jan 21, 2012 at 8:05 Craig asked Jan 21, 2012 at 0:03 CraigCraig 531 silver badge6 bronze badges 6
  • 2 bodyless while loop ... "What fundamental aspect of non-blocking code am I missing?" – Alex Wayne Commented Jan 21, 2012 at 0:22
  • You shouldn't be trying to recreate setTimeout, just use it. It was made for this purpose. – david Commented Jan 21, 2012 at 0:24
  • I guess the idea was to more deeply understand what setTimeout does to keep the event loop going. My hope is that I could then use the same method if I had to do heavy processing with JavaScript server-side. – Craig Commented Jan 21, 2012 at 0:28
  • why do you want to do your own setTimeout? your code will just get stucked in that while. and javascript has no sleep – Hugo Mota Commented Jan 21, 2012 at 0:28
  • 1 What it means to be non blocking in node – Raynos Commented Jan 21, 2012 at 1:09
 |  Show 1 more ment

4 Answers 4

Reset to default 4

In order to not block the event loop your code has to eventually return to the event loop and allow it to continue processing. Unless your code actually returns to the event loop then it can't dequeue the next message and process it. This code won't exit for the given time period and hence never returns control to the event loop.

You've got most of the correct idea - you want to write a function that will execute quickly and then return control back to the main event loop. Instead of the function itself idly waiting (in your case by literally sitting in a while loop and sleeping), it registers a callback -- typically with setTimeout -- and then returns. Then, when the timeout is called it wakes back up and executes whatever function it needs to.

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);
}

maybe a wrapper is what you want?

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

When you call a function you don't start a new thread. Therefore running a while loop inside the wait function will block execution.

本文标签: