首页 > 解决方案 > How does "return Promise.resolve()" affect the JavaScript Event loop?

问题描述

I've been using Javascript for a while, and I understand how the javascript-event-loop works. However, I've come across a case that doesn't totally make sense for me. Consider the following code:

setTimeout(()=> console.log('1'));
Promise.resolve('whatever').then(()=>console.log('2'));
console.log('3');

I expected this output:

3
1
2

However, I run it on chrome js console, and I get the following:

3
2
1

Question: shouldn't "Promise.resolve().then(fn)" either call the function immediately, or insert the function-execution-procedure to the end of the event-loop - the way 'setTimeout' works -, is there something I'm missing ?

标签: javascriptecmascript-6es6-promiseevent-loop

解决方案


Browsers implement multiple job/task queues. The spec requires implementations to maintain two queues:

  1. ScriptQueue
  2. PromiseQueue

There is most likely a TimerQueue (HTML DOM Task Queue) that accommodates the HTML DOM Level 2 Timer spec too. These are each FIFO queues that are populated at runtime and eventually are the event loop queue. Following your code example:

setTimeout(()=> console.log('1'));
Promise.resolve('whatever').then(()=>console.log('2'));
console.log('3');
  • Line 1 pushes onto (likely) a TimerQueue (HTML DOM Task Queue)
  • Line 2 pushes onto the PromiseQueue
  • Line 3 pushed onto the stack and is executed immediately (to completion)

Once the stack is empty, each queue will drain until empty. In your example, the Promise queue empties first and then the TimerQueue empties last.

This can be further demonstrated by extending your example just a bit:

setTimeout(()=> console.log('second from final')); // <-- first item in TimerQueue
Promise.resolve('whatever').then(()=>console.log('2')); //<-- first time in PromiseQueue
setTimeout(()=> console.log('just prior to final')); // <-- second item in TimerQueue
Promise.resolve('whatever').then(()=>console.log('1')); //<-- second item in PromiseQueue
setTimeout(()=> console.log('final')); // <-- third item in ScriptQueue 
console.log('3'); // <-- synchrounous function call placed onto the stack, executed immediately

You should note that order of execution is not guaranteed. The spec does not define the execution order of the queues:

This specification does not define the order in which multiple Job Queues are serviced. An ECMAScript implementation may interweave the FIFO evaluation of the PendingJob records of a Job Queue with the evaluation of the PendingJob records of one or more other Job Queues.

EDIT

After discussion (below) with Bergi I have indicated that browser implementations likely create other queues too. The most likely queue related to this post would be a TimerQueue as a Task Queue that holds the HTML DOM spec'd timer tasks.


推荐阅读