浏览器工作原理

浏览器端的 Event Loop
函数执行栈(主线程)
宏任务队列
微任务队列
宏任务(tasks)
- 分类:
setTimeout、setInterval、setImmediate(Node 独有)、requestAnimationFrame(浏览器独有)、I/O(文件读取等操作)、UI rendering(浏览器独有)- 被放到宏任务队列
- 第一个宏任务队列只有一个任务:执行主线程 js 代码
- 宏任务队列可以有多个
每次只取宏任务队列中的第一个任务出来执行- 当宏任务执行完毕,先去查看是否有微任务,如果有,先去执行微任务队列,否则继续执行下一个宏任务队列
微任务(jobs)
- 分类:
new Promise().then、process.nextTick()(Node 独有)、Object.observe、MutationObserver(浏览器独有)- 被放到微任务队列
- 微任务队列仅有一个
- 在上一个宏任务队列执行完毕,如果有微任务队列就会立即执行
Node.js 中的 Event Loop

Event Loop 过程:
- 执行全局 Script 的同步代码
- 执行 microtask 微任务,先执行所有 Next Tick Queue 中的任务,再执行 Other Microtask Queue 中的所有任务
- 开始执行 macrotask 宏任务,共六个阶段,
每阶段取宏任务队列中的所有任务执行 - Timers Queue -> 步骤二 -> I/O Queue -> 步骤二 -> Check Queue -> 步骤二 -> Close Callback Queue -> 步骤二 -> Timers Queue …

注意:
process.nextTick和then的执行先后
// 执行顺序 1、2,process.nextTick 更快
Promise.resolve(2).then(console.log)
process.nextTick(() => {console.log(1)})
setTimeout(() => {console.log(1)})
setImmediate(() => {console.log(2)})
// 准备时间大于 10 ms,则绝对输出 1、2
const start = Date.now()
while (Date.now() - start > 10) {}
const fs = require('fs')
fs.readFile(__dirname, () => {
// 放置到了 I/O callbacks 之后,绝对输出 2、1
setTimeout(() => {console.log(1)})
setImmediate(() => {console.log(2)})
})
setTimeout和setImmediate的执行先后
setImmediate 方法用于中断长时间运行的操作,并在完成其他操作后立即运行回调函数
// 执行顺序不确定,取决于 node 准备时间
setTimeout(() => {console.log(1)})
setImmediate(() => {console.log(2)})
- 例题
console.time('start')
setTimeout(() => {
console.log(2)
}, 10)
setImmediate(() => {
console.log(1)
})
new Promise(resolve => {
console.log(3)
resolve()
console.log(4)
}).then(() => {
console.log(5)
console.timeEnd('start')
})
console.log(6)
process.nextTick(() => {
console.log(7)
})
console.log(8)
// 3, 4, 6, 8, 7, 5, time, (2, 1)/(1, 2)
版权声明:本文为lucky541788原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。