js事件循环 Event Loop

首先看一段代码:

        console.log('start')
        setTimeout(() => {
            console.log('setTimeout')
        }, 0)
        Promise.resolve().then(() => {
            console.log('promise1')
        }).then(() => {
            console.log('promise2')
        })
        console.log('end')

打印顺序是什么?
正确答案是:

start 
end 
promise1
promise2
setTimeout

原因是:主程序和 settimeout 都是宏任务,两个 then 是微任务。第一个宏任务(主程序)执行完,执行全部的微任务(两个then),再执行下一个宏任务(settimeout)。

任务队列

首先我们需要明白以下几件事情:

  • JS分为同步任务和异步任务
  • 同步任务都在主线程上执行,形成一个执行栈
  • 主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了运行结果,就在任务队列之中放置一个事件。
  • 一旦执行栈中的所有同步任务执行完毕(此时JS引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行。

根据规范,事件循环是通过任务队列的机制来进行协调的。一个 Event Loop 中,可以有一个或者多个任务队列(task queue),一个任务队列便是一系列有序任务(task)的集合;每个任务都有一个任务源(task source),源自同一个任务源的 task 必须放到同一个任务队列,从不同源来的则被添加到不同队列。 setTimeout/Promise 等API便是任务源,而进入任务队列的是他们指定的具体执行任务。

 

 

宏任务 macrotask

(macro)task(又称之为宏任务),可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。

浏览器为了能够使得JS内部(macro)task与DOM任务能够有序的执行,会在一个(macro)task执行结束后,在下一个(macro)task 执行开始前,对页面进行重新渲染,流程如下:

(macro)task->渲染->(macro)task->...

事件队列是事件的回调函数依次存放的地方。事件被调用时,会从事件队列中把对应的回调函数移出推入到函数调用堆栈中执行。

事件队列中的每一个回调函数都是一个 macroTask。

(macro)task主要包含:script(整体代码)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)

宏任务优先级:script(整体代码) > setImmediate > MessageChannel > setTimeout / setInterval

比如:setImmediate指定的回调函数,总是排在setTimeout前面

微任务 microtask

微任务,通常来说是在当前宏任务执行结束后立即执行的任务。比如对一系列动作做出反馈,或者是需要异步的执行任务而又不需要分配一个新的宏任务,这样便可以减小一点性能的开销。只要执行栈中没有其他的js代码正在执行且每个宏任务执行完,微任务队列会立即执行。如果在微任务执行期间微任务队列加入了新的微任务,会将新的微任务加入队列尾部,之后也会被执行。微任务包括了mutation observe的回调还有接下来的例子promise的回调。

microtask主要包含:Promise.then、async 函数中 await 之后的任务、MutaionObserver、process.nextTick(Node.js 环境)

微任务优先级:process.nextTick > Promise.then > MutationObserver

事件循环机制

在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:

  1. 执行一个宏任务(栈中没有就从事件队列中获取)。
  2. 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中。
  3. 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)。
  4. 当前宏任务执行完毕,开始检查渲染,然后 GUI 线程接管渲染。
  5. 渲染完毕后,JS 线程继续接管,开始下一个宏任务(从事件队列中获取)。

注意:宏任务需要多次事件循环才能执行完,微任务是一次性执行完的。

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值