Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javascript promises, the event loop, and the job queue

Tags:

javascript

Consider the following code:

function foo() {
    console.log('foo');

    new Promise(
        function(resolve, reject) {
            setTimeout(function() {
                resolve('RESOLVING');
            }, 5000);
        }
    )
    .then(
        function(value) {
            console.log(value);
        }
    );
}
foo();

I am trying to understand what happens here correctly:

  1. on executing new Promise the "executer function" is run directly and when setTimeout is called, an operation to add a new entry to the "event queue" is scheduled (for 5 seconds later)
  2. because of the call to then an operation to add to a "job queue" a call to the passed function (which logs to the console) is organised to happen after the Promise is resolved
  3. when the setTimeout callback is executed (on some tick of the event loop), the Promise is resolved and based on point 2, the function argument to the then call is added to a "job queue" and subsequently executed.

Notice I say [a "job queue"] because there is something I am not sure about; which "job queue is it?". The way I understand it, a "job queue" is linked to an entry on the "event queue". So would that be the setTimeout entry in above example? Assuming no other events are added to the "event queue" before (and after) setTimeout's callback is added, wouldn't the entry for the main code (the call to foo) have been (usually) gone (run to completion) by that time and thus there would be no other entry than setTimeout's for the then's "job queue" entry to be linked to?

like image 741
3m3sd1 Avatar asked Apr 14 '19 15:04

3m3sd1


People also ask

What is event loop and event queue in JavaScript?

JavaScript has a runtime model based on an event loop, which is responsible for executing the code, collecting and processing events, and executing queued sub-tasks. This model is quite different from models in other languages like C and Java.

How JavaScript works event loop stack and queue how JavaScript code executes?

The Event Loop has one simple job — to monitor the Call Stack and the Callback Queue. If the Call Stack is empty, the Event Loop will take the first event from the queue and will push it to the Call Stack, which effectively runs it. Such an iteration is called a tick in the Event Loop.

What is the event loop in JavaScript?

The event loop is a constantly running process that monitors both the callback queue and the call stack. If the call stack is not empty, the event loop waits until it is empty and places the next function from the callback queue to the call stack.


Video Answer


1 Answers

  1. on executing new Promise the "executer function" is run directly and when setTimeout is called, an operation to add a new entry to the "event queue" is scheduled (for 5 seconds later)

Yes. More specifically, calling setTimeout schedules a timer with the browser's timer mechanism; roughly five seconds later, the timer mechanism adds a job to the main job queue that will call your callback.

  1. because of the call to then an operation to add to a "job queue" a call to the passed function (which logs to the console) is organised to happen after the Promise is resolved

Right. then (with a single argument) adds a fulfillment handler to the promise (and creates another promise that it returns). When the promise resolves, a job to call the handler is added to the job queue (but it's a different job queue).

  1. when the setTimeout callback is executed (on some tick of the event loop), the Promise is resolved and based on point 2, the function argument to the then call is added to a "job queue" and subsequently executed.

Yes, but it's not the same job queue. :-)

The main job queue is where things like event handlers and timer callbacks and such go. The primary event loop picks up a job from the queue, runs it to completion, and then picks up the next job, etc., idling if there are no jobs to run.

Once a job has been run to completion, another loop gets run, which is responsible for running any pending promise jobs that were scheduled during that main job.

In the JavaScript spec, the main job queue is called ScriptJobs, and the promise callback job queue is PromiseJobs. At the end of a ScriptJob, all PromiseJobs that have been queued are executed, before the next ScriptJob. (In the HTML spec, their names are "task" [or "macrotask"] and "microtask".)

And yes, this does mean that if Job A and Job B are both queued, and then Job A gets picked up and schedules a promise callback, that promise callback is run before Job B is run, even though Job B was queued (in the main queue) first.

Notice I say [a "job queue"] because there is something I am not sure about; which "job queue is it?"

Hopefully I covered that above. Basically:

  • Initial script execution, event handlers, timers, and requestAnimationFrame callbacks are queued to the ScriptJobs queue (the main one); they're "macrotasks" (or simply "tasks").
  • Promise callbacks are queued to the PromiseJobs queue, which is processed until empty at the end of a task. Thatis, promise callbacks are "microtasks."

The way I understand it, a "job queue" is linked to an entry on the "event queue".

Those are just different names for the same thing. The JavaScript spec uses the terms "job" and "job queue." The HTML spec uses "tasks" and "task queue" and "event loop". The event loop is what picks up jobs from the ScriptJobs queue.

So would that be the setTimeout entry in above example?

When the timer fires, the job is scheduled in the ScriptJobs queue.

Assuming no other events are added to the "event queue" before (and after) setTimeout's callback is added, wouldn't the entry for the main code (the call to foo) have been (usually) gone (run to completion) by that time and thus there would be no other entry than setTimeout's for the then's "job queue" entry to be linked to?

Basically yes. Let's run it down:

  • The browser loads the script and adds a job to ScriptJobs to run the script's top-level code.
  • The event loop picks up that job and runs it:
    • That code defines foo and calls it.
    • Within foo, you do the console.log and then create a promise.
    • The promise executor schedules a timer callback: that adds a timer to the browser's timer list. It doesn't queue a job yet.
    • then adds a fulfillment handler to the promise.
    • That job ends.
  • Roughly five seconds later, the browser adds a job to ScriptJobs to call your timer callback.
  • The event loop picks up that job and runs it:
    • The callback resolves the promise, which adds a promise fulfillment handler call to the PromiseJobs queue.
    • That job ends, but with entries in PromiseJobs, so the JavaScript engine loops through those in order:
      • It picks up the fulfillment handler callback job and runs it; that fulfillment handler does console.log
    • That job is completely done now.

More to explore:

  • Jobs and Job Queues in the JavaScript specification
  • Event Loops in the HTML5 specification
like image 73
T.J. Crowder Avatar answered Oct 10 '22 15:10

T.J. Crowder