Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js: How would you recreate the 'setTimeout' function without it blocking the event loop?

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.

like image 285
Craig Avatar asked Oct 08 '22 23:10

Craig


1 Answers

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.

like image 69
JaredPar Avatar answered Oct 24 '22 03:10

JaredPar