Node.js event loop

The event loop is one of the most important aspects of understanding nodes


ThisEvent loopIt is one of the most important aspects about Node.

Why is this so important? Because it illustrates how Node implements asynchronous and non-blocking I/O, it basically illustrates Node's "killer application", which is what makes it successful.

The Node.js JavaScript code runs on a single thread. Only one thing happens at a time.

This limitation is actually very useful because it greatly simplifies your programming style without worrying about concurrency issues.

You only need to pay attention to how to write the code and avoid anything that may block the thread, such as synchronous network calls or infinitecycle.

Generally, in most browsers, each browser tab has an event loop to isolate each process and avoid web pages with infinite loops or heavy processing to block your entire browser.

The environment manages multiple concurrent event loops to handle, for example, API calls.Network workerIt can also run in its own event loop.

The main thing you need to worry about isYour codeWill run on a single event loop, and keep this in mind when writing code to avoid blocking it.

Stop the event loop

Any JavaScript code that takes a long time to return control to the event loop will block the execution of any JavaScript code in the page, or even block the UI thread, and the user cannot click to browse, scroll the page, etc.

Almost all I/O primitives in JavaScript are non-blocking. Network requests, file system operations, etc. Blocked is an exception, which is why JavaScript is so much based on callbacks, only recently based onpromisewithAsync/await.

Call stack

The call stack is a LIFO queue (last in, first out).

The event loop is constantly checkedCall stackSee if there are any functions that need to be run.

In doing so, it adds all the function calls it finds to the call stack and executes each function in sequence.

Do you know the error stack trace that you might be familiar with in the debugger or browser console? The browser looks up the function name in the call stack to inform you which function initiated the current call:

Exception call stack

A simple event loop description

Let's take an example:

I usefoo,barwithbazAsRandom name. Enter any names to replace them.

const bar = () => console.log('bar')

const baz = () => console.log(‘baz’)

const foo = () => { console.log(‘foo’) bar() baz() }


This code prints


As expected.

When this code runs, firstfoo()Called. insidefoo()Let's call firstbar()And then we callbaz().

At this point, the call stack looks like this:

Call stack first example

The event loop in each iteration checks whether there is something in the call stack and executes it:

Execution order first example

Until the call stack is empty.

Queuing function execution

The above example looks normal, nothing special: JavaScript finds things to execute and runs them in order.

Let's see how to defer the function until the stack is cleared.

ExamplesetTimeout(() => {}), 0)Just call a function, but once every other function in the code is executed, execute it.

for example:

const bar = () => console.log('bar')

const baz = () => console.log(‘baz’)

const foo = () => { console.log(‘foo’) setTimeout(bar, 0) baz() }


This code prints out, perhaps surprisingly:


When this code is run, foo() will be called first. Inside foo(), we first call setTimeout,barAs a parameter, we instruct it to run as fast as possible and pass 0 as the timer. Then we call baz().

At this point, the call stack looks like this:

Call stack second example

This is the order of execution of all functions in the program:

Execution order second example

Why is this so?

message queue

When calling setTimeout(), Browser or Node.js will startTimer. After the timer expires, in this case, we immediately set the timeout value to 0, and then put the callback function intomessage queue.

The message queue is also a user-initiated event, such as a click or keyboard event, orBring itQueuing the responses before your code has a chance to respond to them. Or alsoDOMEvents like thisonLoad.

The loop assigns priority to the call stack. It first processes everything found in the call stack, and once there is nothing in it, it starts processing the content in the message queue.

We don't have to wait for things likesetTimeout, Crawling or other ways to do your own work, because they are provided by the browser, and they are in their own thread. For example, if you setsetTimeoutThe timeout is 2 seconds, you don't have to wait 2 seconds-the wait happens elsewhere.

ES6 job queue

ECMAScript 2015The concept of job queue is introduced, and Promises uses this queue (also introduced in ES6/ES2015). This is a way to execute the result of an asynchronous function as quickly as possible, rather than at the end of the call stack.

Promises resolved before the end of the current function will be executed immediately after the current function.

I find the roller coaster analogy in an amusement park is good: the message queue puts you behind the queue, behind everyone else, you will have to wait for the turn, and the work queue is a fast-track ticket so you can finish Ride another ride immediately after one ride.


const bar = () => console.log('bar')

const baz = () => console.log(‘baz’)

const foo = () => { console.log(‘foo’) setTimeout(bar, 0) new Promise((resolve, reject) => resolve(‘should be right after baz, before bar’) ).then(resolve => console.log(resolve)) baz() }


This print

should be right after baz, before bar

This is Promises (and Async/await built on Promise) and throughsetTimeout()Or other platform APIs.

in conclusion

This article introduces you to the basic building blocks of the Node.js event loop.

This is an important part of any program written in Node.js, and I hope that some of the concepts presented here will be useful to you in the future.

Download mine for freeNode.js manual

More node tutorials: