每个事件循环都有一个微任务队列和一个宏任务队列。
微任务是原本要在微任务队列而不是任务队列上排队的任务。请参阅https://www.w3.org/TR/html51/webappapis.html#microtask-queue。
有两种微任务:
- 单独回调微任务,例如
Promise
,
- 和复合微任务,例如Node.js 中的
Object.observe
、MutationObserver
和process.nextTick
。
而宏任务队列主要包含setTimeout
, setInterval
, setImmediate
, requestAnimationFrame
,I/O
在 Nodejs 中。
在一个事件循环中,这两个任务队列将分两步运行:
- 首先检查旧的宏任务队列中是否有宏任务(称为X);
- 如果X存在并且正在运行,则等待它进入下一步,直到它完成;否则,立即进入下一步;
- 其次,运行微任务队列的所有微任务;
- 当运行微任务时,我们仍然可以向队列中添加更多的微任务,这些任务也会运行。
在你的例子中:
- 首先,您的 Promise 初始化
new Promise
并且resolve
是同步的;
- 然后同步添加一个
setTimeout
macroTask到macrotask队列中;
- 然后将微
promise.then(function(){})
任务同步添加到微任务队列中,这个任务会立即运行,因为 Promise 的初始化和解析是同步的,这个任务在任何宏任务之前运行;所以, console.log p1 fulfilled
;
- 然后将第二个宏
setTimeout
任务添加到宏任务队列中;
- 在这个事件循环结束后,运行两个宏任务;
对于此代码:
setTimeout(function(){
console.log("will be executed at the top of the next Event Loop")
},0)
var p1 = new Promise(function(resolve, reject){
setTimeout(function(){resolve(1)},0)
});
setTimeout(function(){
console.log("will be executed at the bottom of the next Event Loop")
},0)
for (var i = 0; i < 100; i++) {
(function(j){
p1.then(function(value){
console.log("promise then - " + j)
});
})(i)
}
输出顺序:
will be executed at the top of the next Event Loop
promise then - 0
promise then - 1
promise then - 2
...
promise then - 99
will be executed at the bottom of the next Event Loop
- 首先将三个
setTimeout
macrotask添加promise.then()
到macrotask queue ,一个microtask添加到microtask queue;
- 运行宏任务;
- 如果条件为真,则运行所有微任务,但为假,则进行下一步;
- 运行第二个宏任务;
- 检查 promise 是否已解决,条件为真,然后运行所有微任务;
- 继续运行其他宏任务;