简体   繁体   中英

Why does a promise inside setTimeout resolve before a subsequent setTimeout function?

Run the following code in browser or node.js:

 setTimeout(() => { console.log(1); Promise.resolve().then(() => { console.log(2); }); }); setTimeout(() => { console.log(3); });

Promise callbacks and timer callbacks are scheduled differently from each other.

Promise handler functions are called asynchronously at the end of the task that scheduled them. You're scheduling two tasks (the timer callbacks). In the first task, since the promise is already fulfilled, the callback to the fulfillment handler happens asynchronously at the end of the task (it's a so-called microtask ). Then the next task (the next timer callback) happens.

So your code executes like this:

  1. The task for executing your script runs:
    1. It schedules the timer callback for the first setTiemout .
    2. It schedules the timer callback for the second setTiemout .
    3. The task ends
  2. The task for the first timer callback runs:
    1. It does console.log(1)
    2. It creates a fulfilled promise
    3. It attaches a fulfillment handler to that promise
      1. Since the promise is already fulfilled, this schedules a microtask to call the handler
    4. The task ends
    5. The microtask queued by the task runs, doing console.log(2)
  3. The task for the second timer callback runs:
    1. And logs console.log(3)

For browsers, you can find the details of this process in the Event Loops section of the specification.

It's worth noting that microtasks scheduled during a microtask run in the same "clear out the microtask queue" step as the microtask that scheduled them, before the next (macro)task runs. Consequently, the following gives us 1 2a 2b 3 rather than 1 2a 3 2b as you might otherwise expect:

 setTimeout(() => { console.log(1); Promise.resolve().then(() => { console.log("2a"); }).then(() => { console.log("2b"); }); }, 0); setTimeout(() => { console.log(3); }, 0);

as does this (because it's largely the same thing):

 setTimeout(() => { console.log(1); Promise.resolve().then(() => { console.log("2a"); Promise.resolve().then(() => { console.log("2b"); }); }); }, 0); setTimeout(() => { console.log(3); }, 0);

UPDATE WITH DIAGRAMS:

Yes, that's because Promise.resolve() has a different queue called the JOB QUEUE or MICROTASK QUEUE , and this Job Queue has the higher Priority than the Callbacks Queue . Note that we are dealing with Promises now and not the callbacks when we do Promise.Resolve: So Javascript ES6 came up with this Job Queue to handle Promises differently and call backs differently :)

So, Event Loop is going to check the Job Queue first and make sure there is nothing in that Queue before it starts looking, at the Call back Queue . So that the Job Queue has higher Priority than the call back queue.

工作队列

I want to give an example to make it more clear because I feel that will make it explain more clearly.

 setTimeout(()=>console.log("This is line 1")); Promise.resolve("Two").then(data=>console.log("I am ",data)); setTimeout(()=>console.log("I am third"));

In the above code snippet, Promise is resolved first and only then the other setTimeout. That's because of the

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM