浏览器 Javascript 的 EventLoop 动态图析

3,284 阅读3分钟

欢迎访问我的博客看原文...摸我
学习node eventLoop的童鞋请注意区分噢....本文代码都只在浏览器下进行


任务分类

宏任务(macrotask)

  • setTimeOutsetIntervalsetImmediateI/O 、 各种callbackUI渲染等
  • 优先级: 主代码块 > setImmediate > MessageChannel > setTimeOut/setInterval

微任务(microtask)

  • process.nextTickPromiseMutationObserverasync(实质上也是promise)
  • 优先级: process.nextTick > Promise > MutationOberser

执行分区

我们常常吧EventLoop中分为 内存、执行栈、WebApi、异步回调队列(包括微任务队列和宏任务队列)

执行栈

  • 执行栈是宏任务被执行的地方

宏任务 & 宏任务队列

  • 宏任务总会在下一个EventLoop中执行
  • 若在执行宏任务的过程中,加入了新的微任务,会把新的微任务添加到微任务的队列中。

微任务 & 微任务队列

  • 若在执行微任务的过程中,加入了新的微任务,会把新的微任务添加在当前任务队列的队尾巴。
  • 微任务会在本轮EventLoop执行完后,马上把执行栈中的任务都执行完毕。

执行流程

Javascript内核加载代码到执行栈
执行栈依次执行主线程的同步任务,过程中若遇调用了异步Api则会添加回调事件到回调队列中。且微任务事件添加到微任务队列中,宏任务事件添加到宏任务队列中去。直到当前执行栈中代码执行完毕。
③ 开始执行当前所有微任务队列中的微任务回调事件。 (:smirk:注意是所有哦,相当于清空队列)
④ 取出宏任务队列中的第一条(先进先出原则哦)宏任务,放到执行栈中执行。
⑤ 执行当前执行栈中的宏任务,若此过程总又再遇到微任务或者宏任务,继续把微任务宏任务进行各自队伍的入队操作,然后本轮的宏任务执行完后,又把本轮产生的微任务一次性出队都执行了。
⑥ 以上操作往复循环...就是我们平时说的eventLoop

....特点是

  • 微任务队列操作,总是会一次性清空队列
  • 宏任务队列每次只会取出一条任务到执行栈中执行

辅助理解

let promiseGlobal = new Promise(resolve=>{
  console.log(1)
  resolve('2')
})
console.log(3) 

promiseGlobal.then(data=>{
  console.log(data)
  let setTimeoutInner = setTimeout(_=>{
  console.log(4)
   },1000)
   let promiseInner =new Promise(resolve=>{
     console.log(5) 
      resolve(6)
    }).then(data=>{
     console.log(data)
   })
})
let setTimeoutGlobal = setTimeout(_=>{
  console.log(7);
 let promiseInGlobalTimeout = new Promise(resolve=>{
      console.log(8); 
      resolve(9)
  }).then(data=>{
     console.log(data)
  })
},1000) 

建议不要直接拷贝到 控制台跑...大家先想想:smirk:

过程动画

答案

1 3 2 5 6 __ 等待一秒___ 7 8 9 4


其他相关

setTimeout

Q: 我的setTimeout函数到时间了,为啥一直不去执行。

A: setTimeOut的回调会被放到任务队列中,需要当前的执行栈执行完了,才会去执行执行任务队列中的内容。出现setTimeout回调不及时,说明在执行栈中出现了阻塞,或者说执行代码过多。

nextTick

常见的vue.$nextTick会把事件直接插入到当前微任务队列的中,感兴趣的请看我的笔记《vue_nextTick与eventLoop》 传送门--> 和 《vue_DOM更新与nextTick》传送门-->


其他文章

欢迎star我的github

async/await 实现异步编程

你了解GET和POST吗

veu_nextTick与eventLoop