- 执行栈和事件队列 当js调用一个函数的时候会产生执行环境,即执行上下文,被执行的方法被推到一个执行栈中依次执行。 当碰到异步任务的时候,会将这些任务放到event quene中,即事件队列中。
异步任务有分为宏任务和微任务,会被分别放在各自对应的event queue。
执行完同步任务后,会找到微任务队列,如果队列中存在对应事件,则先执行微任务,当微任务列表清空后会执行下一个宏任务。
常见的微任务有: promise、MutaionObserver等 常见的宏任务有: setInterval、setTimeout等
- 举例
console.log(1)
setTimeout(() => {
console.log(2)
}, 0)
new Promise((resolve, reject) => {
console.log(3)
resolve(3)
}).then(res => {
console.log(4)
})
上述代码会优先执行调用栈中的同步任务,即1, 3
promise中函数会立即执行,也属于同步任务,所以会先输出3。
之后查找微任务队列里的任务,清空微任务列表,之后会输出4, 最后输出宏任务的3。所以最后结果是1342。
在看一个复杂的例子
console.log(1)
let timer1 = setTimeout(() => {
console.log(2)
let promise3 = new Promise((resolve, reject) => {
console.log(3)
resolve(3)
}).then(res => {
console.log(4)
let promise4 = new Promise((resolve, reject) => {
console.log(11)
resolve(11)
}).then(() => {
console.log(12)
})
})
}, 0)
let promise1 = new Promise((resolve, reject) => {
console.log(5)
resolve()
}).then(res => {
console.log(6)
let timer2 = setTimeout(() => {
console.log(7)
let promise2 = new Promise((resolve, reject) => {
console.log(8)
resolve()
}).then(res => {
console.log(9)
})
}, 0)
})
console.log(10)
- 首先执行执行栈中的任务,所以会先输出 1 5 10;同时现在任务队列里被同时放进一个宏任务,一个微任务。
| 宏任务队列 | 微任务队列 |
|---|---|
| timer1 | promise1 |
- 之后会执行微任务队列里面的任务,所以先输出6,然后又遇到一个宏任务timer2,放到宏任务队列,此时微任务队列里任务清空。
| 宏任务队列 | 微任务队列 |
|---|---|
| timer1 | |
| timer2 |
- 此时将宏任务队列里的timer1取出来,放到执行栈中执行,会输出2 3,然后又遇到一个微任务promise3, 将promise3放入微任务队列。
| 宏任务队列 | 微任务队列 |
|---|---|
| timer2 | promise3 |
- 执行完一个宏任务,下次事件循环该清空微任务队列里,此时微任务队列里有一个promise3,执行promise3输出4, 同时又遇到一个微任务放到微任务队列中,此时微任务队列未清空,所以继续执行微任务队列里的任务,直至微任务队列清空。所以会输出11 12
| 宏任务队列 | 微任务队列 |
|---|---|
| timer2 |
- 微任务队列清空,下面会执行宏任务timer2,其中timer2中又有一个微任务所以会输出7 8 9
所以这个列子最后输出的结果是 1、5、10、6、2、3、4、11、12、7、8、9