javascript - 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 ?
解决方案
Browsers implement multiple job/task queues. The spec requires implementations to maintain two queues:
- ScriptQueue
- 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.
推荐阅读
- android - 隐藏控件时亚马逊 Fire TV 遥控器不会暂停 ExoPlayer
- html - CSS 显示网格高度问题。3998px 是网格的最大高度吗?
- rpm - 如何通过自动下载/安装其他依赖项来安装本地 .rpm 文件
- c - 结果的类型是什么?可能吗?
- apache-spark - 使用结构化流一次将所有数据写入镶木地板文件
- ansible - 使用 Ansible-Playbook 接受 Splunk 许可协议
- java - Springboot中使用@ConfigurationProperties和@PropertySource时如何将属性序列化为对象?
- javascript - 如何在javascript中组合多个数组?
- python-3.x - 从 AWS Lambda 上的 S3 读取文件时出现 IncompleteReadError
- python-sphinx - 狮身人面像在 TOC 中不显示本地标题