js运行机制
首先我们知道,在js运行的时候,会有一个主线程,这个主线程在由上向下执行js代码的时候,如果遇到异步任务,会把异步任务交给异步线程去处理,异步任务执行之后,如果有回调,就会把回调放到任务队列里去.等待主线程执行栈里的东西执行完了,就用任务队列里从前往后取需要执行的任务,放到主线程里执行.由此形成一个循环.这个循环就是EventLoop.
在这里要提到一点,主线程里面执行的任务和任务队列里的任务都是宏任务,每执行一个宏任务V8引擎就会创建一个栈,并且V8会为每一个宏任务创建一个微任务,等宏任务执行栈里的内容执行完了,会先去执行这个微任务,等微任务再执行完了,就销毁执行栈,并且去任务队列里取下一个宏任务执行.
![](https://img2022.cnblogs.com/blog/1996608/202207/1996608-20220714224405886-224330802.png)
宏任务包括:
- script(整体代码)
- setTimeout, setInterval, setImmediate,
- I/O
- UI rendering
微任务包括:
- process.nextTick
- Promise
- Object.observe(已废弃)
- MutationObserver(html5新特性)
async函数的本质:
async函数还是基于Promise的一些封装,而Promise是属于微任务的一种;因此会把await func()
后面的所有代码放到Promise的then回调函数中去
举个例子:
async function async1(){
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start')
async1()
console.log('script end')
//script start
//async1 start
//async2
//script end
//async1 end
以上代码可以写成这样:
async function async1() {
console.log('async1 start')
new Promise(function(resolve){
console.log('async2')
resolve()
}).then(function(){
console.log('async1 end')
})
}
console.log('script start')
async1()
console.log('script end')
以上都了解完之后 做个面试题:
async function async1(){
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start')
setTimeout(function(){
console.log('setTimeOut')
}, 0)
async1()
new Promise(function(resolve){
console.log('promise1')
resolve()
}).then(function(){
console.log('promise2')
})
console.log('script end')
结果是:
1 //script start
2 //async1 start
3 //async2
4 //promise1
5 //script end
6 //async1 end
7 //promise2
8 //setTimeOut
解析过程就是:
- 第一轮循环开始
- 打印
script start
- 发现setTimeout,放入宏任务1
- 打印
async1 start
- 打印
async2
- 把await async2函数后面的回调放入微任务1
- 打印
promise1
- 把then中的函数放入微任务2
- 打印
script en
- 调用栈清空,开始执行微任务1,打印
async1 end
- 执行微任务2,打印
promise2
- 微任务执行完,第一轮循环结束
- 开始宏任务1,打印
setTimeOut
参考链接:https://xieyufei.com/2019/12/30/Quiz-Eventloop.html