JS运行机制
事件循环
定义:JavaScrript有一个基于事件循环的并发模型,事件循环负责执行代码、收集和处理事件以及执行队列中的子任务。
首先来看一下这个模型:
栈:函数调用形成了一个由若干帧组成的栈;
堆:对象被分配在堆中,用来表示一大块内存区域的计算机术语;
队列:一个JavaScript运行的时候包含了一个待处理消息的队列,而每一个消息都关联着一个用于处理这个消息的回调函数;(消息队列也叫任务队列)
事件循环:之所以称之为 事件循环,是因为它经常按照类似如下的方式来被实现:
while (queue.waitForMessage()) {
queue.processNextMessage();
}
复制代码
再结合以下代码进行分析:
function foo(b) {
let a = 10;
return a + b + 11;
}
function bar(x) {
let y = 3;
return foo(x * y);
}
console.log(bar(7)); // 返回 42
复制代码
在事件循环期间的某个时刻,运行时会从最新进入队列的消息开始处理。被处理的消息会被移出队列,并作为输入参数来调用与之关联的函数。
对以上这段代码的执行顺序进行分析:
- 当调用
console.log(bar(7))
时,产生一个消息,进入消息队列; - 当调用
bar
的时候,第一个帧被创建并压入栈中,帧中包含了bar
的参数和局部变量; - 当
bar
调用foo
时,第二个帧被创建并被压入栈中,放在第一个帧上,帧中包含了foo
的参数和局部变量; - 当
foo
执行完毕后返回时,第二个帧出栈,当bar
执行完毕返回后,第一个帧出栈,此时栈被清空; - 所有执行栈清空后,这个消息执行结束,事件循环将会处理消息队列中的下一个消息(如果还有的话);
tips:在上面这段代码中,整个过程中只产生了一个任务。
宏任务与微任务
宏任务:
定义:每次执行栈执行的代码就是一个宏任务,宏任务是浏览器规定的;
可以生成宏任务的场景:setTimeout、setInterval、Ajax、DOM 事件
微任务
定义:在当前宏任务结束后立即执行的任务,微任务是由JS语法规定的;
可以生成微任务的场景:Promise async/await
执行顺序
宏任务和微任务的执行顺序:
- 执行一个宏任务;
- 如果执行宏任务的过程中遇到了微任务,将微任务添加到微任务队列中;
- 当前宏任务执行完毕后,立即去执行微任务队里中的微任务;
- 微任务执行完毕后,如果有宏任务的话再去执行下一个宏任务;
所以说:微任务早于宏任务执行
示例
console.log('1')
new Promise((resolve, reject) => {
resolve('2')
}).then((res) => {
console.log(res)
})
setTimeout(() => {
console.log('3')
})
new Promise((resolve, reject) => {
resolve('4')
}).then((res) => {
console.log(res)
})
console.log('5')
复制代码
以上代码的执行结果为1,5,2,4,3
参考文档
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END