25

How do I create a non-blocking asynchronous function? Below is what I'm trying to achieve but my program is still blocking...

var sys = require("sys");

function doSomething() {
  sys.puts("why does this block?");
  while(true);
}

setTimeout(doSomething,0);
setTimeout(doSomething,0);
setTimeout(doSomething,0);

sys.puts("main");
Richard
  • 251
  • 1
  • 3
  • 3
  • The given example will block at while loop which runs forever. See also https://stackoverflow.com/questions/34824460/why-does-a-while-loop-block-the-event-loop – Marcus Apr 03 '19 at 23:13

10 Answers10

35

Cross-posted from Reddit.


The purpose of asynchronous functions in JavaScript is a little bit different from what you seek.

Remember that JavaScript is single-threaded — it can only do one thing at a time. Here is some traditional, blocking code:

sys.puts("Before");
sleep(10);
sys.puts("After");

In a real-world web application, the sleep() might instead be a time-consuming database call, network request (like waiting for data from the user’s web browser), helper tool, or file access.

If you used blocking calls like the above, the Node.js server would’t be able to do anything else (like starting to handle other web requests) while waiting.

PHP and many other web programming environments handle this by creating totally separate threads for each request. Node.js uses callback functions. You could write the same code like this, instead:

sys.puts("Before");
setTimeout(function(){
    sys.puts("After");
}, 10000);

Here, you create a function and pass it to setTimeout(). Its code hasn’t run yet, but when it does, it will have access to all the scope (all the variables) where it was created. setTimeout() gets a reference to the function and schedules an event to fire on the event loop after the timeout expires.

The event loop is, essentially, a Node.js program’s to-do list (they’re common — all the GUI applications running on your computer probably use event loops!).

After the call to setTimeout(), the current function keeps executing. It eventually returns, and the function which called it returns, and so on, until the program ends up back in the event loop. The event loop looks to see if anything has happened (e.g. an incoming request) while your code was executing, and calls the appropriate function in your code. If not, it waits until something does happen (like the timeout expiring).

Asynchronous code doesn’t let your code do many things at the same time, it does eliminate blocking when some code depends on something external to continue.

It’s rare that you need to do blocking work inside your Node.js program. If you do, you should separate that work out into a separate process (which can even be another Node.js program), or write a C/C++ addon which is free to use threads.

s4y
  • 50,525
  • 12
  • 70
  • 98
  • 1
    Ah! Now I understand it more clearly. Thanks for the explanation; your third-last paragraph was especially useful. +1 – Paul d'Aoust Nov 04 '11 at 20:28
17

You can only do asynchronous IO in node.js by using asynchronous IO functions provided by node.js runtime or node.js extensions written in C++. Your own Javascript code is always synchronous in node.js. Asynchronous non-IO code is rarely needed, and node.js designers decided to avoid it at all.

There are some arcane ways of running Javascript asynchronously in node.js, mentioned by other commenters, but node.js is not designed for this type of work. Use Erlang if you need that type of concurrency, node.js is only about paralell IO, and for parallel computations it is just as bad as Python or PHP.

nponeccop
  • 13,527
  • 1
  • 44
  • 106
  • Great answer, I have one question : Is mongo db operation in Node.js is asynchronous IO ? – Dhiral Pandya Dec 30 '14 at 09:37
  • 1
    Yes. `.connect` and `.insert` for example are asynchronous functions. See http://mongodb.github.io/node-mongodb-native/2.0/overview/quickstart/ – nponeccop Dec 30 '14 at 18:15
11

You need to run your blocking function in a separate process.

This module can help: http://github.com/cramforce/node-worker

Felix Geisendörfer
  • 2,902
  • 5
  • 27
  • 36
  • 27
    It's important to understand that node isn't about functions being asynchronous all the time. It's about *i/o* being asynchronous and non-blocking. If your function doesn't do any i/o, node isn't going to help you make it asynchronous. It provides tools that will allow you to do that though. Like child processes. That's what felix's answer is getting at. Your function can spawn a child process to do your work and it will execute off of the main event loop. – Marco May 22 '10 at 14:23
6

If you don't want to use the WebWorker API / node-worker, which is still very alpha, just create an additional node program and communicate via TCP or HTTP.

This allows you to dispatch your work as HTTP calls or raw TCP data and asynchronously wait for the HTTP response / incoming TCP answer.

Note however, this is only appropriate if your task is easily serializable.

b_erb
  • 20,932
  • 8
  • 55
  • 64
4

setTimeout will not create a new thread, so the browser will still hang at the infinite loop.

You need to rethink your program structure.

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • Do you have any idea how I go about achieving this in node.js? Thanks – Richard May 20 '10 at 21:37
  • 1
    This question is pretty old, but still very interesting for node.js beginners like me.. As mentioned node.js is for parallel I/O not parallel working. That means: If you have a time consuming job to do to respond to a single request node.js will not speed up what you try to achieve in that single request. The difference between using sleep() and setTimeout() ist that node.js will block all other requests when using sleep() for the time of sleeping - using setTimeout() will not block other requests. Or: 10 requests to sleep(10s) will take 100s - 10 requests to setTimeout(10s) only 10s. – schlicki Mar 04 '16 at 19:49
2

You can do this without using a child process using nextTick()

I was just reading this explanation the other day about nextTick... it's a great read IMO

---edit: old link is dead. Found a new one right on StackOverflow

understanding the node.js event queue and process.nextTick

ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
1

If i do understand what you're after, you have two functions (both take a callback as argument):

process.nextTick: this function can be stacked, meaning that if it is called recursively, it will loop a huge (process.maxTickDepth) number of times per tick of the event loop.

or

setImmediate: this function is much closer to setting a 0 timeout (but happens before).

In most cases, you should prefer setImmediate.

Sheraff
  • 5,730
  • 3
  • 28
  • 53
0

I am assuming you are experimenting with Nodejs also I am assuming that you are not writing any npm module itself and exporting your function as asynchronous function, In practical you will not encounter such case, if you want to do any blocking operations in the functions or in the callbacks which are executed in a single thread environment, try to use appropriate node modules like fs for file reading, request for network request and async module which gives various types of async operations, also remember you are trying to execute cpu consuming code asynchronously it is a bad idea, because 2HZ can execute a million lines of code in just less than microseconds

The main purpose of nodejs is to solve the problem you have asked in the question which is handled by the underlying libuv to handle asynchronous events, I appreciate the answer of using set time out, but you do not know how much time to wait for or using node worker is fine but you will end up writing lot of boiler plate code, so simply search for the npm module that would satisfy your need.

murali kurapati
  • 1,510
  • 18
  • 23
0

Try to answer this question based on the event loop model (the core of node.js).

setTimeout(doSomething,0). Yes, setTimeout will add a task into the task queue. And after 0 second, the time is up. Event loop checks the task queues and finds the task is done, and its callback function doSomething is ready to run.

The above process is async.

One thing needs to note here is: the callback function doSomething runs on the main thread(or the single thread) of node.js, and the event loop is also running on this thread. Without a doubt, the while(true) loop totally block the thread.

Chris Bao
  • 2,418
  • 8
  • 35
  • 62
-6

This line:

while(true);

isn't "blocking", it's just busy, forever.

Matt Ranney
  • 1,638
  • 12
  • 12