What is the difference between "event loop queue" and "job queue"?
Asked Answered
R

6

37

I can not understand how the following code run. Why "1" is after "b" but "h" is after "3"?

Shouldn’t the order be a, b, 1, 2, h, 3? Some articles said that the difference between "event loop queue" and "job queue" leads to the following output. But how? I have read the specification of ECMAScript 2015 - 8.4 Jobs and Job Queues, wanting to know how Promise'job works, but it makes me more confused. How can I fix this?

var promise = new Promise(function(resolve, reject) {resolve(1)});
promise.then(function(resolve) {console.log(1)});
console.log('a');
promise.then(function(resolve) {console.log(2);});
setTimeout(function() {console.log('h')}, 0);
promise.then(function(resolve) {console.log(3)});
console.log('b');

// a
// b
// 1
// 2
// 3
// h

I know Promise is asynchronous, but the callback of the setTimeout(..) asynchronous operation is always after Promise's asynchronous operation. Why?

Ricoriki answered 30/11, 2016 at 4:38 Comment(2)
Promise's are asynchronous - even inline synchronous looking code like that, the .then is called asynchronously - that's what promises doCandlepin
Please prettify this code :/Metatherian
T
25

Why "1" is after "b"?

The promise specification states that all promise .then() handlers must be called asynchronously after the call stack has emptied. Thus, both a and b, which are executed synchronously on the call stack will execute before any .then() handlers so 1 will always be after a and b.

Some interesting reading:

  1. Tasks, microtasks, queues and schedules.
  2. What is the order of execution in JavaScript promises?
  3. Writing a JavaScript framework - Execution timing, beyond setTimeout.

There's some good advice here in the thread "Promises wiggle their way between nextTick and setImmediate":

I would not recommend relying on the exact execution order of non-chained events. If you want to control the execution order - rearrange the callbacks in a way so that the one that you want to be executed later depends on the one that you want to be executed earlier, or implement a queue (that does the same behind the hood).

In other words, if you depend upon a particular ordering of asynchronous events, then you should actually chain them rather than relying on unspecified scheduling in the implementation.

Tyler answered 30/11, 2016 at 4:56 Comment(7)
why is h after 3 :pCandlepin
@JaromandaX, most likely the job queue of JS implementations have a higher priority than event queues implemented by the browsers. But not really sure.Rollet
@JaromandaX - That is a slightly different question than what the OP asked. I'd have to do some research to figure out whether that is by specification or is implementation-specific based on how .then() handlers are queued vs. setTimeout() events.Tyler
@JaromandaX Promise will add a job to the job queue, but the setTimeout will put the function to the end of the event loop, when time expired. when a job is added to the job queue, javascript engine will take the next job on the job queue and only when job queue is empty , it moves to the next entry on the event loop. Each slot on the event loop has its own job queueWithrow
@JaromandaX - Tasks vs. micro-tasks. It looks like the ordering is by convention (and not followed universally), not specification.Tyler
That is a slightly different question than what the OP asked. - yep, I didn't notice the specific 1 after b part of the question -all goodCandlepin
Added several more references about how various asynchronous things are scheduled.Tyler
D
15

In HTML terms, the event loop for a page or set of pages from the same domain can have multiple task queues. Tasks from the same task source always go into the same queue, with the browser choosing which task queue to use next.

Tasks to run timer call backs come from the timer task source and go in the same queue. Let's call this queue task queue "A".

The ECMAscript 2015 (ES6) specification requires tasks to run Promise reaction callbacks to form their own job queue called "PromiseJobs". ECMAscript and HTML specifications do not use the same language, so let's notionally equate ECMA's "Promise Job queue" with HTML task queue "B" in the browser - at least a different queue to the one used by timers.

Theoretically a browser could choose tasks from either queue A or B to run, but in practice the promise task queue gets higher priority and will empty before a timer call back gets run.

This is why "h" gets logged last. Promise then calls on fulfilled promises place jobs in the promise queue, which get executed with higher priority than timer call backs. The promise queue only becomes empty after console.log(3) has been executed, which allows the timer call back to execute.


Advanced

ECMAScript guardians chose not to use HTML5 terminology or description of task queues in their specification because ECMAScript can run in more environments than just HTML browsers.

Native implementation of promise queues may use a "micro task" queue instead of a separate dedicated promise task queue. Micro queued jobs are simply run after the current script thread and any tasks previously added to the micro queue complete.

Detail of micro task queuing is not required to understand promises.

Promise polyfills for browsers which lack native support for promises (all versions of IE etc) may use timers and not behave in exactly the same way as native implementations when it comes to the order of promise reactions and timer call backs.

Dropsonde answered 30/11, 2016 at 7:24 Comment(0)
A
10

As of ES6, a job queue runtime was added to accommodate the promises. With new Promise() we handle async code natively. setTimeout is not part of JavaScript; it is part of the web API which is provided by the browser.

Now we have two queues. A callback queue and a job queue. The job queue is also called the micro task queue.

The key thing is here, the job queue has higher priority over callback queue. So in your example, the first synchronous code is executed.

 console.log('a');  // a
 console.log('b');  // b

Then promises are sent to the job queue and setTimeout() is sent to the callback queue. Now the event loop checks the job queue first regardless of how long the setTimeout() is set for. Since the queues implement "first in first out", they are executed as they are ordered since they are just logging to the console.

promise.then(function(resolve) {console.log(1)}); // 1
promise.then(function(resolve) {console.log(2)}); // 2
promise.then(function(resolve) {console.log(3)}); // 3

After the job queue is cleared out, the event loop checks the callback queue:

setTimeout(function() {console.log('h')}, 0); // h
Abrahan answered 11/9, 2020 at 7:31 Comment(0)
B
4

I found this one easy to understand for someone new to JavaScript.

This is copy paste from @getify's book:

to use a metaphor: the event loop queue is like an amusement park ride, where once you finish the ride, you have to go to the back of the line to ride again. But the Job queue is like finishing the ride, but then cutting in line and getting right back on.

event loop queue - for all async callbacks other than promises, h

job queue - for all async callbacks related to promises. 1, 2, 3

Sync - a, b

Broil answered 28/1, 2018 at 17:28 Comment(3)
Have the last three lines also been copied?Trapezohedron
Related: What do we do with answers that are entirely copied and improperly attributed (only a "reference" link or similar is included)?Trapezohedron
What is "getify's book"?Trapezohedron
B
4

ES6 has two queues:

  1. A callback queue
  2. A job queue (microtask queue)

Both setTimeout and a promise are async code.

In setTimeout we explicitly specify the function to be autorun when the background web browser API work is finished (in setTimeout's case, it’s the Timer feature of web browser API). Once the timer has done its job, it pushes the function onto the callback queue and has to wait until all the sync code of JavaScript has completed. That’s why.

console.log("a")
console.log("b")

gets done first.

Now coming to the promise part, any promise in JavaScript does two things:

  1. Sets the background API feature
  2. returns a promise object

The .then() specifies which function to be run once the promise has been resolved, but not immediately.

The function specified inside the .then() gets pushed inside the Job queue on task completion.

Once all the sync code in JavaScript is completed, the event loop checks the job queue first and then the callback queue. So that’s why 'h' is logged at the very end.

Babe answered 13/9, 2021 at 5:43 Comment(0)
H
1

In JavaScript Runtime, the Job Queue is created with Task Queue during the JavaScript Runtime, which is much similar to the task queue, but it has priority over the task queue.

This means the JavaScript event loop first looks into the job queue. If there is any task in the job queue, the event loop will check the stack. If the stack is empty, it will push the task from the job queue into the stack. After that, the event loop checks the job queue again.

If the job queue is empty, the event loop checks the task queue. If there is any task, the task will be pushed to the stack for execution. The job queue is added in JavaScript Runtime in the ES6 for the execution of promises.

For example:

var promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('promise win')
    }, 4000)
})
promise.then((result) => {
    console.log(result)
})
setTimeout(() => {
    console.log('setTimeout win')
}, 4000)

Output:

promise win

setTimeout win

Explanation:

Both the setTimeout and promise are executed asynchronously, and both take the same amount of time. However, promises are executed first, and then callbacks. This is because promises are moved to the job queue, while setTimeout is moved to the callBack queue.

These queues are created during JavaScript runtime to perform tasks asynchronously. The Web API handles this process. Since the Job Queue has priority over the task queue, promises get executed before the callbacks.

Housebroken answered 29/7, 2021 at 15:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.