1 前言
原文链接: https://juejin.im/post/59e85eebf265da430d571f89
要想弄懂promise、setTimeout这一系列的执行顺序,绕不开事件循环机制。而这篇掘金的文章是我看到的解释事件循环机制中最通俗易懂的一篇,推荐给大家。
说明:作者写得非常棒,不过有几个地方是像我一样的新手需要注意的,在此补充出来。
(1) Node与浏览器对于宏任务、微任务的执行机制是不一样的。比如以下代码
console.log('1')
setTimeout(function() {
console.log('2')
process.nextTick(function() {
console.log('3')
})
new Promise(function(resolve) {
console.log('4')
resolve()
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6')
})
new Promise(function(resolve) {
console.log('7')
resolve()
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9')
process.nextTick(function() {
console.log('10')
})
new Promise(function(resolve) {
console.log('11')
resolve()
}).then(function() {
console.log('12')
})
})
在Node中执行结果是1 7 6 8 2 4 9 11 3 10 5 12
在Vue/浏览器中执行结果是1 7 6 8 2 4 3 5 9 11 10 12
原因在于Node先在宏队列中一次性执行所有同类任务,再在微队列中执行所有同类任务,同类指的是优先级。nextTick>then,所以结果是3 10 5 12而不是3 5 10 12。而在浏览器中,微任务相当于是在宏任务间隙执行,一个宏->对应的微任务,下一个宏->对应的微任务…
(2) 调用resolve()才会执行then()
setTimeout(function() {
console.log('setTimeout');
})
new Promise(function(resolve) {
console.log('promise');
}).then(function() {
console.log('then');
})
console.log('console');
这段代码执行结果是promise console setTimeout,要加上resolve才会在第三位输出then.
2 总结
2.1 什么是事件循环?
(1) 同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
(2) 注册完成后,Event Table会将这个函数移入Event Queue。
(3) 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
上述过程会不断重复,也就是常说的Event Loop(事件循环)。
2.2 事件循环、宏任务、微任务关系
备注:
macro-task(宏任务):包括整体代码script,setTimeout,setInterval
micro-task(微任务):Promise,process.nextTick
不同类型的任务会进入对应的Event Queue,比如setTimeout和setInterval会进入相同的Event Queue。事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。图片理解可结合前言中的第一点。