vlambda博客
学习文章列表

JS基础:Event loop事件循环解析

在node v12版本后,浏览器端与node端Event loop实现保持一致,在这篇文章我们将综合讨论,异步任务事件队列一般有两种,一种是macro(宏任务)事件队列,另一种是micro(微任务)事件队列。宏任务事件队列可以有多个但是微任务事件队列一般只有一个。

  • 宏任务事件 script(全局事件)、setTimeout、setInterval、I/O操作、UI渲染
  • 微任务事件 new Promise().then、process.nextTick() node端 一个完整的Event Loop过程,可以概括为以下阶段:
  • 一开始执行栈空,micro队列空,macro只有一个script脚本(全局代码)
  • 全局上下文(script标签)被压入执行栈中,同步任务开始执行,在执行的过程中,会判断是同步任务还是异步任务,如果是异步任务则进一步区分是宏任务还是微任务,如果是宏任务则放入macro队列里,如果是微任务则放入micro队列里,同步代码执行完毕,script则被macro task移除,
  • 下一步开始执行micro队列,这里需要注意的是浏览器执行宏任务是一个接着一个执行的,执行完一个之后再将微任务队列全部清空,再执行下面的宏任务
  • 执行渲染操作,更新界面,上述过程执行完毕,直至队列清空
    <script>
        console.log('1');
        setTimeout(()=>{
            console.log('2');
            new Promise((resolve)=>{
              console.log('3');
              resolve();
            }).then(()=>{
                console.log('4');
            })
        },10);
        new Promise((resolve)=>{
            console.log('5');
            resolve();
        }).then(()=>{
            console.log('6')
        })
        setTimeout(()=>{
            console.log('7');
            new Promise((resolve)=>{
              console.log('8');
              resolve();
            }).then(()=>{
            console.log('9');
            })
        },10);
        console.log('10');
    </script>

让我们开始做题

  • 一开始执行script标签,这是宏任务,打印1,碰到setTimeout事件是宏任务记为setTimeout1进入宏任务队列里,new Promise()立即执行打印5,then事件进入微任务队列里,继续执行碰到setTimeout事件是宏任务记为setTimeout2,进入宏任务队列里,继续往下执行打印10
  • 开始询问微任务队列是否为空,不为空,打印6,此时微任务队列已空,开始执行下个宏任务
  • 开始执行setTimeout1宏任务,打印2,new Promise()立即执行打印3,回调then加入微任务队列里,此时该宏任务执行完毕,询问微任务队列是否为空,不为空,执行微任务队列,打印4.此时宏任务执行完毕开始执行下个宏任务
  • 开始执行setTimeout2宏任务,打印7,new Promise()立即执行,打印8,回调then加入微任务队列里,此时该宏任务执行完毕打印,询问微任务队列是否为空,不为空,执行微任务队列,打印9.