https://juejin.im/post/5da742936fb9a04e223333ff(摘自掘金)
主线程、任务队列(Macrotask和Microtask)
Macrotask常见的任务:
setTimeout,setInterval,setImmediate,I/O,用户交互操作和UI渲染
Microtask常见的任务:
Promise(重点),process.nextTick(nodejs),Object.observe(不推荐使用)
事件循环执行流程
- 检查Macrotask队列是否为空,若不为空,则进行下一步,若为空,则跳到3
- 从Macrotask队列中取队首(在队列时间最长)的任务进去执行栈中执行(仅仅一个),执行完后进入下一步
- 检查Microtask队列是否为空,若不为空,则进入下一步,否则,跳到1(开始新的事件循环)
- 从Microtask队列中取队首(在队列事件最长)的任务进去事件队列执行,执行完后,跳到3其中,在执行代码过程中新增的microtask任务会在当前事件循环周期内执行,而新增的macrotask任务只能等到下一个事件循环才能执行了。
简而言之,一次时间循环只执行处于Macrotask队首的任务,执行完成后,立即执行Microtask队列中的所有任务。
eg1
console.log(1)
setTimeout(function() {
//settimeout1
console.log(2)
}, 0);
const intervalId = setInterval(function() {
//setinterval1
console.log(3)
}, 0)
setTimeout(function() {
//settimeout2
console.log(10)
new Promise(function(resolve) {
//promise1
console.log(11)
resolve()
})
.then(function() {
console.log(12)
})
.then(function() {
console.log(13)
clearInterval(intervalId)
})
}, 0);
//promise2
Promise.resolve()
.then(function() {
console.log(7)
})
.then(function() {
console.log(8)
})
console.log(9)
//
1
9
7
8
2
3
10
11
12
13
在上面的例子中
- 第一次事件循环:
- console.log(1) 被执行,输出1
- settmeout1执行,加入大队列
- setinterval1执行,加入大队列
- settimeout2执行,加入大队列
- promise2执行,它的两个then函数加入小队列
- console.log(9)执行,输出9
- 根据事件循环的定义,接下来会执行新增的小任务,按照进入队列的顺序,执行console.log(7)和console.log(8)小任务队列为空,进入下一个事件循环 此时大任务队列为: settimeout1,setinterval1,settimeout2
第二次事件循环:
大任务队列中取队首(settimeout1)执行,输出2,
小任务队列为空,进入下一个事件循环 此时大任务队列为:setinterval1,settimeout2第三次事件循环:
(setinterval1)执行,输出3<br /> 小任务队列为空,进入下一个事件循环 此时大任务队列为:settimeout2,setinterval1
第四次循环
(settimeout2)执行,输出10,11,12,13