JS学习笔记—JS 的 Event Loop

执行栈和Event Loop

行栈是一个存储函数调用的栈结构,遵循先进后出的原则。当开始执行 JS 代码时,首先会执行一个 main 函数,然后执行我们的代码。根据先进后出的原则,后执行的函数会先弹出栈。

当遇到异步的代码时,会被挂起并在需要执行的时候加入到 Task(有多种 Task) 队列中。一旦执行栈为空,Event Loop 就会从 Task 队列中拿出需要执行的代码并放入执行栈中执行,所以本质上来说 JS 中的异步还是同步行为。

不同的任务源会被分配到不同的 Task 队列中,任务源可以分为 微任务(microtask) 和 宏任务(macrotask)。在 ES6 规范中,microtask 称为 jobs,macrotask 称为 task

Event Loop 处在两者之间,扮演一个大管家的角色,它会以一个固定的时间间隔不断轮询,当它发现主线程空闲,就会去到 Task 队列里拿一个异步回调,把它塞入执行栈中执行,一段时间后,主线程执行完成,弹出上下文环境,再次空闲,Event Loop 又会执行同样的操作。。。依次循环,于是构成了一套完整的事件循环运行机制。

Event Loop执行顺序

    console.log('script start')

    async function async1() {
      await async2()               //执行完后返回了一个Promise.resolve(undefined),该回调被推入 microtask ,async1 函数中的执行权被让出,等待主线程空闲
      console.log('async1 end')
    }
    async function async2() {
      console.log('async2 end')
    }
    async1()

    setTimeout(function() {        //引擎解析至 setTimeout,等待 0ms 后将其回调推入 macrotask,执行权继续让出
      console.log('setTimeout')
    }, 0)

    new Promise(resolve => {        //解析进入注入函数的内部,碰到 console.log,于是打印 Promise,再往下,碰到了 resolve,此时,该回调被推入 microtask ,执行权被让出
      console.log('Promise')
      resolve()
    })
      .then(function() {
        console.log('promise1')
      })
      .then(function() {
        console.log('promise2')
      })

    console.log('script end')        //至此,主线程空闲,Event Loop 事件循环启动,开始从 microtask 里拿出 promise 回调,放入主线程执行
// log 打印顺序:script start -> async2 end -> Promise -> script end -> async1 end-> promise1 -> promise2 -> setTimeout

 

首先拿出最早注入的 async2Promise.resolve(undefined)执行,此时 await 操作符解析该表达式,得到结果 undefined,并将 async1 [Promise] 函数 标志为 resolve 状态,将 await 后面的代码作为回调,继续推入 microtask,等待执行,执行权被让出

此时主线程没有可执行的代码,再次空闲,Event Loop 启动,去 microtask 中拿到之前的 new Promise 回调,放入主线程执行,打印结果 promise1 和 promise2;

主线程空闲,Event Loop 去 microtask 里拿 aysnc1 的回调,打印出 async1 end

最后,主线程空闲,microtask 队列空,Event Loop 去 macrotask 里拿到 setTimeout 的回调,放入主线程,打印最后的 setTimeout

最新版的 chrome 浏览器对于 await 的处理变快了,async1 end 会先于 promise 1 打印)。

Event Loop 执行顺序如下所示:

  • 首先执行同步代码,这属于宏任务
  • 当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行
  • 执行所有微任务
  • 当执行完所有微任务后,如有必要会渲染页面
  • 然后开始下一轮 Event Loop,执行宏任务中的异步代码,也就是 setTimeout 中的回调函数

微任务包括 process.nextTick ,promise ,MutationObserver,其中 process.nextTick 为 Node 独有。

宏任务包括 script , setTimeout ,setInterval ,setImmediate ,I/O ,UI rendering

推荐文章链接:https://juejin.im/post/5c7e3fdbf265da2dca38856e

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值