How to write a non-blocking callback in Javascript?

Here is some code I am trying :

startTask();

function startTask(){
    console.log('startTask enter');
    startLongTask(1, function(){
        console.log('long task complete');
    });
    console.log('startTask exit');
}

function startLongTask(i, callback) {
    while (i++ < 10000){
        console.log(i);
    }
    callback();
}

And here is the output (omitting the large series on numbers):

startTask enter
2
3
4
5
6
7
8
9
10
long task complete
startTask exit

As evident, if I have a long running operation, it's synchronous. It's like having startLongTask inline in startTask. How do I fix this callback to be non-blocking. The output I expect is :

startTask enter
startTask exit
2
3
4
5
6
7
8
9
10
long task complete

Javascript-only code does not have the ability to create new asynchronous operations in pure JS because the V8 interpreter in node.js does not give you full-fledged threads.

Libraries such as the fs module in node.js get their async behavior from native operations (outside of the JS/V8 world) and they interface to the JS engine with an async interface.

That said, there are ways you can run operations in the background in node.js by using some non-JS code. You can start another process, you can use a variety of add-on modules that support other threads of execution, etc... All of these will go outside of pure node.js Javascript in order to offer an async interface.

If your task can be broken into short chunks, you can also simulate an asynchronous operation by doing small amounts of work on successive timers (this is a common work-around in the browser too).

You can use a timeout function with 0 milliseconds delay. Any functions in the timeout will be pushed to the end of the execution thread. e.g.

startTask();

function startTask(){
    console.log('startTask enter');
    setTimeout(function(){
        startLongTask(1, function(){
            console.log('long task complete');
        })
    }, 0);
    console.log('startTask exit');
}

function startLongTask(i, callback) {
    while (i++ < 100){
        console.log(i);
    }
    callback();
}

You could use a Web Worker to push startLongTask() onto another thread, but beware that there are some restrictions in using a Web Worker. Or you could push the startLongTask() functionality into a service that your main thread can call asynchronously and then use a callback to handle the result.

JavaScript is very async around I/O operations.