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:
- on executing
new Promise
the "executer function" is run directly and whensetTimeout
is called, an operation to add a new entry to the "event queue" is scheduled (for 5 seconds later) - 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 thePromise
is resolved - when the
setTimeout
callback is executed (on some tick of the event loop), thePromise
is resolved and based on point 2, the function argument to thethen
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 pletion) 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?
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:
- on executing
new Promise
the "executer function" is run directly and whensetTimeout
is called, an operation to add a new entry to the "event queue" is scheduled (for 5 seconds later) - 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 thePromise
is resolved - when the
setTimeout
callback is executed (on some tick of the event loop), thePromise
is resolved and based on point 2, the function argument to thethen
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 pletion) 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?
- Are you asking about a particular implementation? Or for a language-lawyer definition from some standard? – Ivan Rubinson Commented Apr 14, 2019 at 15:27
- @IvanRubinson A browser like Chrome – 3m3sd1 Commented Apr 14, 2019 at 15:29
- So Googles V8 engine. – Ivan Rubinson Commented Apr 14, 2019 at 15:30
- @IvanRubinson would there be that much difference in implementation between different browsers/engines? Is the behaviour not expected to be the same across the board for described scenario? – 3m3sd1 Commented Apr 14, 2019 at 15:32
- 1 @jonathan no, promises always resolve asynchronously – Jonas Wilms Commented Apr 14, 2019 at 16:39
1 Answer
Reset to default 7
- on executing
new Promise
the "executer function" is run directly and whensetTimeout
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.
- 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 thePromise
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).
- when the
setTimeout
callback is executed (on some tick of the event loop), thePromise
is resolved and based on point 2, the function argument to thethen
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 pletion, and then picks up the next job, etc., idling if there are no jobs to run.
Once a job has been run to pletion, 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 pletion) by that time and thus there would be no other entry thansetTimeout
's for thethen
'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 theconsole.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.
- That code defines
- 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
- It picks up the fulfillment handler callback job and runs it; that fulfillment handler does
- That job is pletely done now.
More to explore:
- Jobs and Job Queues in the JavaScript specification
- Event Loops in the HTML5 specification
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745464730a4628866.html
评论列表(0条)