Event Loop (事件循环机制)

浏览器工作原理

Event Loop (事件循环机制)_第1张图片

浏览器端的 Event Loop

函数执行栈(主线程)
宏任务队列
微任务队列

宏任务(tasks)

  • 分类:setTimeout、setInterval、setImmediate(Node 独有)、requestAnimationFrame(浏览器独有)、I/O(文件读取等操作)、UI rendering(浏览器独有)
    1. 被放到宏任务队列
    2. 第一个宏任务队列只有一个任务:执行主线程 js 代码
    3. 宏任务队列可以有多个
    4. 每次只取宏任务队列中的第一个任务出来执行
    5. 当宏任务执行完毕,先去查看是否有微任务,如果有,先去执行微任务队列,否则继续执行下一个宏任务队列

微任务(jobs)

  • 分类:new Promise().then、process.nextTick()(Node 独有)、Object.observe、MutationObserver(浏览器独有)
    1. 被放到微任务队列
    2. 微任务队列仅有一个
    3. 在上一个宏任务队列执行完毕,如果有微任务队列就会立即执行

Node.js 中的 Event Loop

Event Loop (事件循环机制)_第2张图片
Event Loop 过程:

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

Event Loop (事件循环机制)_第3张图片

注意:

  • process.nextTickthen 的执行先后
// 执行顺序 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)})
})
  • setTimeoutsetImmediate 的执行先后
    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)

你可能感兴趣的:(javascript)