js事件循环 - 图1

https://juejin.im/post/5da742936fb9a04e223333ff(摘自掘金)

主线程、任务队列(Macrotask和Microtask)

  1. Macrotask常见的任务:
  2. setTimeout,setInterval,setImmediate,I/O,用户交互操作和UI渲染
  1. Microtask常见的任务:
  2. Promise(重点),process.nextTick(nodejs),Object.observe(不推荐使用)

事件循环执行流程

  1. 检查Macrotask队列是否为空,若不为空,则进行下一步,若为空,则跳到3
  2. 从Macrotask队列中取队首(在队列时间最长)的任务进去执行栈中执行(仅仅一个),执行完后进入下一步
  3. 检查Microtask队列是否为空,若不为空,则进入下一步,否则,跳到1(开始新的事件循环)
  4. 从Microtask队列中取队首(在队列事件最长)的任务进去事件队列执行,执行完后,跳到3其中,在执行代码过程中新增的microtask任务会在当前事件循环周期内执行,而新增的macrotask任务只能等到下一个事件循环才能执行了。

    简而言之,一次时间循环只执行处于Macrotask队首的任务,执行完成后,立即执行Microtask队列中的所有任务。

eg1

  1. console.log(1)
  2. setTimeout(function() {
  3. //settimeout1
  4. console.log(2)
  5. }, 0);
  6. const intervalId = setInterval(function() {
  7. //setinterval1
  8. console.log(3)
  9. }, 0)
  10. setTimeout(function() {
  11. //settimeout2
  12. console.log(10)
  13. new Promise(function(resolve) {
  14. //promise1
  15. console.log(11)
  16. resolve()
  17. })
  18. .then(function() {
  19. console.log(12)
  20. })
  21. .then(function() {
  22. console.log(13)
  23. clearInterval(intervalId)
  24. })
  25. }, 0);
  26. //promise2
  27. Promise.resolve()
  28. .then(function() {
  29. console.log(7)
  30. })
  31. .then(function() {
  32. console.log(8)
  33. })
  34. console.log(9)
  1. //
  2. 1
  3. 9
  4. 7
  5. 8
  6. 2
  7. 3
  8. 10
  9. 11
  10. 12
  11. 13

在上面的例子中

  • 第一次事件循环:
  1. console.log(1) 被执行,输出1
  2. settmeout1执行,加入大队列
  3. setinterval1执行,加入大队列
  4. settimeout2执行,加入大队列
  5. promise2执行,它的两个then函数加入小队列
  6. console.log(9)执行,输出9
  7. 根据事件循环的定义,接下来会执行新增的小任务,按照进入队列的顺序,执行console.log(7)和console.log(8)小任务队列为空,进入下一个事件循环 此时大任务队列为: settimeout1,setinterval1,settimeout2
  • 第二次事件循环:

    大任务队列中取队首(settimeout1)执行,输出2,
    小任务队列为空,进入下一个事件循环 此时大任务队列为:setinterval1,settimeout2

  • 第三次事件循环:

    1. (setinterval1)执行,输出3<br /> 小任务队列为空,进入下一个事件循环 此时大任务队列为:settimeout2setinterval1
  • 第四次循环

    1. (settimeout2)执行,输出10,11,12,13