Promises, Next-Ticks, and Immediates— NodeJS Event Loop Part 3
Tags: node, javascript
Published: 2019-12-05 23:49:28

Welcome back to the Event Loop article series! In the first article of the series, we discussed the overall picture of the Node JS event loop and it’s different stages. Later in the second article, we discussed what timers and immediates are in the context of the event loop and how each queue is scheduled. In this article, let’s look at how event loop schedules resolved/rejected promises (including native JS promises, Q promises, and Bluebird promises) and next tick callbacks. If you are not familiar with Promises yet, I suggest you should first get in touch with Promises. Believe me, it’s so cool!!

## Post Series Roadmap

*   [Event Loop and the Big Picture](https://blog.insiderattack.net/event-loop-and-the-big-picture-nodejs-event-loop-part-1-1cb67a182810)
*   [Timers, Immediates and Next Ticks](https://blog.insiderattack.net/timers-immediates-and-process-nexttick-nodejs-event-loop-part-2-2c53fd511bb3)
*   **Promises, Next-Ticks, and Immediates (This article)**
*   [Handling I/O](https://blog.insiderattack.net/handling-io-nodejs-event-loop-part-4-418062f917d1)
*   [Event Loop Best Practices](https://blog.insiderattack.net/event-loop-best-practices-nodejs-event-loop-part-5-e29b2b50bfe2)
*   [New changes to timers and microtasks in Node v11](https://blog.insiderattack.net/new-changes-to-timers-and-microtasks-from-node-v11-0-0-and-above-68d112743eb3)

# Native Promises

> There are some changes introduced in Node v11 which significantly changes the execution order of `nextTick`, `Promise` callbacks, `setImmediate` and `setTimeout` callbacks since Node v11\. Read more:

{% medium https://medium.com/@dpjayasekara/new-changes-to-timers-and-microtasks-from-node-v11-0-0-and-above-68d112743eb3 %}

In the context of native promises, a promise callback is considered as a microtask and queued in a microtask queue which will be processed right after the next tick queue.

<noscript><img class="dq t u ei ak" src="https://miro.medium.com/max/1902/1*4rN4DDM9LoXcLHWa_HX28Q.png" width="951" height="526" role="presentation"/></noscript>

Consider the following example.

{% gist https://gist.github.com/deepal/4521d73cb0d4529de06358ee0344d90f %}

In the above example, the following actions will happen.

1.  **Five** handlers will be added to the resolved promises microtask queue. (Note that I add 5 resolve handlers to 5 promises which are already resolved)
2.  **Two** handlers will be added to the `setImmediate` queue.
3.  **Three** items will be added to the `process.nextTick` queue.
4.  **One** timer is created with expiration time as zero, which will be immediately expired and the callback is added to the timers queue
5.  **Two** items will be added again to the `setImmediate` queue.

Then the event loop will start checking the `process.nextTick` queue.

1.  Loop will identify that there are three items in the `process.nextTick` queue and Node will start processing the nextTick queue until it is exhausted.
2.  Then the loop will check the promises microtask queue and identify there are five items in the promises microtask queue and will start processing the queue.
3.  During the process of promises microtask queue, **one** item is again added to the `process.nextTick`queue (‘next tick inside promise resolve handler’).
4.  After promises microtask queue is finished, event loop will again detect that there is **one** item is in the `process.nextTick` queue which was added during promises microtask processing. Then node will process the remaining 1 item in the nextTick queue.
5.  Enough of promises and nextTicks. There are no more microtasks left. Then the event loop moves to the first phase, which is the **timers** phase. At this moment it will see there is an expired timer callback in the timers queue and it will process the callback.
6.  Now that there are no more timer callbacks left, loop will wait for I/O. Since we do not have any pending I/O, the loop will then move on to process `setImmediate` queue. It will see that there are **four** items in the immediates queue and will process them until the immediate queue is exhausted.
7.  At last, loop is done with everything…Then the program gracefully exits.

> **Enough of seeing the two words “promises microtask” everywhere instead of just “microtask”?**
> 
> I know it’s a pain to see it everywhere, but you know that resolved/rejected promises and `_process.nextTick_` are both microtasks. Therefore, trust me, I can’t just say nextTick queue and microtask queue.

So let’s see how the output will look like for the above example.


```
next tick1
next tick2
next tick3
promise1 resolved
promise2 resolved
promise3 resolved
promise4 resolved
promise5 resolved
next tick inside promise resolve handler
set timeout
set immediate1
set immediate2
set immediate3
set immediate4
```


# Q and Bluebird

Cool! We now know that the resolve/reject callbacks of JS native promises will be scheduled as a microtask and will be processed before the loop moves to a new phase. So what about **Q** and **Bluebird**?

Before JS native promises were implemented in NodeJS, prehistoric people were using libraries such as **Q** and **Bluebird** (Pun intended :P). Since these libraries predate native promises, they have different semantics than the native promises.

At the time of this writing, **Q (**v1.5.0) uses `process.nextTick` queue to schedule callbacks for resolved/rejected promises. Based on the Q docs,

> Note that resolution of a promise is always asynchronous: that is, the fulfillment or rejection handler will always be called in the next turn of the event loop (i.e. `process.nextTick` in Node). This gives you a nice guarantee when mentally tracing the flow of your code, namely that `then` will always return before either handler is executed.

On the other hands, **Bluebird,** at the time of this writing (v3.5.0) uses `setImmediate` by default to schedule promise callbacks in recent NodeJS versions (you can see the code [here](https://github.com/petkaantonov/bluebird/blob/master/src/schedule.js#L12)).

To see the picture clear, we’ll have a look at another example.

{% gist https://gist.github.com/deepal/f8bc26268635a59f9a0c7d3eb41759be %}

In the above example, `BlueBird.resolve().then` callback has the same semantics as the following `setImmediate` call. Therefore, bluebird’s callback is scheduled in the same immediates queue before the `setImmediate` callback. Since Q uses `process.nextTick` to schedule its resolve/reject callbacks, `Q.resolve().then` is scheduled in the nextTick queue before the succeeding `process.nextTick` callback. We can conclude our deductions by seeing the actual output of the above program, as follows:


```
q promise resolved
next tick
native promise resolved
set timeout
bluebird promise resolved
set immediate
```


> Please note that although I have used only promise `resolve` handlers in the above examples, this behavior is identical for promise `reject` handlers as well. At the end of this article, I’ll present you an example with both resolve and reject handlers

Bluebird, however, provides us a choice. We can select our own scheduling mechanism. Does it mean we can instruct bluebird to use `process.nextTick` instead of `setImmediate`? Yes it does. Bluebird provides an API method named `setScheduler` which accepts a function which overrides the default `setImmediate` scheduler.

To use `process.nextTick` as the scheduler in bluebird you can specify,


```js
constBlueBird = require('bluebird');
BlueBird.setScheduler(process.nextTick);
```


and to use `setTimeout` as the scheduler in bluebird you can use the following code,


```js
constBlueBird = require('bluebird');
BlueBird.setScheduler((fn) => {
    setTimeout(fn, 0);
});
```


_— To prevent this post from being too long, I’m not going to describe examples of different bluebird schedulers here. You can try out using different schedulers and observe the output yourself —_

Using `setImmediate` instead of `process.nextTick` has its advantages too in latest node versions. Since NodeJS v0.12 and above does not implement `process.maxTickDepth` parameter, excessively adding events to the nextTick queue can cause I/O starvation in the event loop. Therefore, it’s safe to use `setImmediate` instead of `process.nextTick` in the latest node versions because immediates queue is processed right after I/O if there are no nextTick callbacks and `setImmediate` will never starve I/O.

## One last twist!

If you run the following program you might run into a bit of a mind-twisting output.

{% gist https://gist.github.com/deepal/4cc950cd58265345f1b0f618c3267c46 %}


```
q promise resolved
q promise rejected
next tick
native promise resolved
native promise rejected
set timeout
bluebird promise resolved
bluebird promise rejected
set immediate
```


Now you should have two questions?

1.  If Q uses `process.nextTick` internally to schedule a resolved/rejected promise callback, how did the log line, `q promise rejected` come before the line, `next tick`?
2.  If Bluebird uses `setImmediate` internally to schedule a resolved/rejected promise callback, how did the line, `bluebird promise rejected` come before the line, `set immediate`.

This is because both libraries internally queue resolved/rejected promise callbacks in an internal data structure and use either `process.nextTick` or `setImmediate` to process all the callbacks in the data structure at once.


Great! Now that you know a lot about `setTimeout`, `setImmediate`, `process.nextTick` and promises, you should be able to clearly explain a given example of these. If you have any question regarding this article or something to be added, I appreciate if you post them in response. In the next article, I’ll discuss how I/O is processed with the event loop in detail. And believe me, It will be an awesome topic!

## References

*   Bluebird Docs [http://bluebirdjs.com/docs/](http://bluebirdjs.com/docs/)
*   Bluebird Git Repo [https://github.com/petkaantonov/bluebird](https://github.com/petkaantonov/bluebird)
*   Q Git Repo [https://github.com/kriskowal/q](https://github.com/kriskowal/q)

Background Image Courtesy: [https://wallpapersite.com/images/wallpapers/the-flash-5120x2880-grant-gustin-season-3-hd-7576.jpg](https://wallpapersite.com/images/wallpapers/the-flash-5120x2880-grant-gustin-season-3-hd-7576.jpg)