美文网首页让前端飞Web 前端开发
对于事件循环机制的补充

对于事件循环机制的补充

作者: ac68882199a1 | 来源:发表于2018-04-01 20:17 被阅读46次

    在之前的一篇文章中,小次简单的介绍了 Javascript 中的 Event Loop,没看过的小伙伴可以点击下方传送门:

    Javascript 基础夯实——理解 Event Loop、Micro Task & Macro Task

    上周有一位小伙伴来找小次对这个话题又进行了一番探讨,内容是关于在 Macro Task 执行时,如果有新的 Micro Task 入栈,那么这个新任务会在什么时间执行呢?

    下面是一种可能存在的情况:

    function macro () {
      setTimeout(() => {
          micro()
        })
    }
    
    function micro () {
        new Promise.resolve().then(() => {
          ...
        })
    }
    
    macro()
    

    可能存在的情况

    1. 当前 Macro Task 栈中有多个任务时,新的 Micro Task 将会在所有 Marco Task 完成之后的下一次主任务及 UI 渲染之间执行
    1. 新的 Micro Task 会在当前正在执行的 Macro Task 结束之后执行,并且如果 Micro Task 中有更新 UI 的任务,剩余的 Macro Task 会在 UI 更新完成后执行

    当然,情况可能并不只有上面两种。但是可以发现的是,上面两种情况中都没有提到 Main Task 的执行时机,因为只要 Main Task 存在,它就会在当前任务执行完毕后立即执行,优先级是最高的。

    下面就验证一下上面两种情况的猜测是否正确。

    验证代码

    // html
    <p id="test"></p>
    
    // javascript
    const $test = document.getElementById('test')
    let counter = 0
    
    function func1 () {
      $test.innerText = ++counter
      alert('func1')
    }
    
    function func2 () {
      $test.innerText = ++counter
      alert('func2')
    }
    
    function func3 () {
      $test.innerText = ++counter
      alert('func3')
    }
    
    function func4 () {
      $test.innerText = ++counter
      alert('func4')
    }
    
    (function () {
      // main task
      func1()
    
      // macro task
      setTimeout(() => {
        func2()
        // micro task
        Promise.resolve().then(func4)
        Promise.resolve().then(func3)
      }, 0)
    
      // macro task
      setTimeout(func1, 0)
    
      // micro task
      Promise.resolve().then(func3)
    
      // main task
      func4()
    })()
    

    上面的代码中,在 setTimeout 执行时,向 Micro Task 中添加了两个任务,并且不管是执行 Main Task,Macro Task 还是 Micro Task 都会对 UI 进行更新,这也能够更方便我们理清楚 UI 更新的时机。

    在代码中使用 alert,是为了能够更明显地看到 UI 更新的情况,因为 alert 会阻塞代码和 UI 的更新

    下面直接看上面验证代码的执行情况:

    1  - alert func1
    2  - alert func4
    3  - alert func3
    4  - UI update -- counter = 3
    5  - alert func2
    6  - alert func4
    7  - alert func3
    8  - UI update -- counter = 6
    9  - alert func1
    10 - UI update -- counter = 7
    

    总结一下上面验证代码得出的结论:

    如果在 Macro 中有新的 Micro 入栈,Micro 的执行总是在 Macro 之前,并且会在 Micro 全部执行完毕后才会更新 UI 和执行下一个 Macro

    扫码关注微信公众号【前端程序员的斜杠青年进化录】 微信扫码,给我赞赏一下~

    相关文章

      网友评论

        本文标题:对于事件循环机制的补充

        本文链接:https://www.haomeiwen.com/subject/wmeacftx.html