likes
comments
collection
share

Event-Loop、宏任务、微任务到底是个啥?

作者站长头像
站长
· 阅读数 17

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情

前言

众所周知,JavaScript是个单线程的脚本语言,通俗点说就是一般情况下,代码都是一行一行执行的,前期的CV工作中确实也是这么干的,后面随着接触了ajax请求、setTimeout、promise、async/await等等,随着而来的就是Event-Loop、宏任务、微任务这些概念,所以此次就针对这些概念做一个总结分享。

Event-Loop

Event-Loop即事件循环,是JavaScript为解决异步编程的一种机制。先看下同步代码的执行流程:

先上三行代码:

console.log('Hello World')

setTimeout(function fun1(){console.log('Timer1')},0)

console.log('你好')

结果: hello World 你好 Timer1

结果想必都毋庸置疑,但是为什么定时器设置了0秒,还是最后才被执行呢,接下来我们就探讨下。

以如下图所示类比JS引擎:

Event-Loop、宏任务、微任务到底是个啥?

Brower:浏览器

call Stack:调用栈,所有JS代码都要先放到调用栈,才能被依次执行

webAPIs:可以理解为JS引擎中处理BOM、DOM节点、事件监听、回调函数等等的一种标准和规范。

callback Queue:顾名思义就是回调队列

Event-Loop:事件循环或者轮询,这里可以理解为同步回调队列与调用栈的一通信机制

在代码被编译执行的时候,是被一并送到调用栈中的,所以最初的调用栈是这样的:

Event-Loop、宏任务、微任务到底是个啥?

接下来就是依次执行,先打印Hello World,调用栈遇到异步函数,发现它有一个回调函数fun1,此时将回调函数fun1,放到web APIs,等时间到达定时函数规定的时间,便把fun1推送到回调队列中(callback Queue),当call Stack中的同步代码执行完毕之后,call Stack 为空,再基于事件循环,也就是Event Loop机制,轮询callback Queue,发现有fun1,便再次推送到调用栈中,具体如下图所示: Event-Loop、宏任务、微任务到底是个啥?

又回到调用栈,按照同步代码依次执行的原理,再执行fun1,打印“Timer1”:

Event-Loop、宏任务、微任务到底是个啥?

这也正好印证了,为什么即便是定时器设置了0秒,也是先执行两个同步的console.log函数,再执行定时器中的回调函数,也是Event Loop的作用所在。 总结一下:

1、同步代码一行一行放到调用栈

2、遇到异步任务,记录到web APIs中,等待时机

3、“时机”到了就推送到回调队列中

4、如果call Stack执行完毕,Event-Loop开始工作,轮询callback Queue,如果不为空,则将任务推送到call Stack中

5、然后Event-Loop继续轮询查找

DOM事件与Event-Loop

    console.log('1111')
    document.getElementById('btn').addEventListener('click', () => {
        console.log('2222')
    })
    console.log('3333')

这里获取DOM节点,添加点击事件,也可以用Event-Loop解释,不同于setTimeout等函数,这里的回调什么时候被放到callback Queue,取决于什么时候触发点击事件。

macroTask 宏任务 与 microTask 微任务

先上代码:

    console.log('100')
    setTimeout(() => {
        console.log('200')
    })
    Promise.resolve().then(() => {
        console.log('300')
    })
    console.log('400')

100和400的执行我们好理解,那200和300谁先执行呢?

先来一些概念:

宏任务:setTimeout、setInterval、Ajax、DOM事件

微任务:Promise async/await

ps:微任务执行时间要比比宏任务早

所以上述代码的打印顺序就是100、200、300、200

Evevt-Loop 与 DOM渲染的关系

前面说到了JS代码的执行顺序,那页面的DOM渲染又该什么时候执行呢,JS引擎是这么规定的,当call Stack(调用栈)第一次执行同步代码完毕,也就是Empty为空的时候,先去尝试进行DOM渲染,再去触发Event-Loop,再执行宏任务,因为Event-Loop类似一种循环机制,所以当宏任务在调用栈中执行完后,再去DOM渲染,Event-Loop再去查找,如此循环往复。 即每次调用栈为空,都是DOM渲染的机会,如果DOM结构有改变,再触发下一次的Event-Loop

当加入了Promise之后,也就是微任务之后,它与DOM渲染的顺序又是怎么样的呢?先说结果

同步代码>>微任务>>DOM渲染>>宏任务

这是因为,当执行到Promise时,它会根据执行“时机”放到microTask Queue中,也就是不会经过web APIs(web APIs是W3C规范,Promise(微任务)是ES6规范,不是W3C规范,宏任务是由浏览器规定的)

这也就是为何——微任务>>DOM渲染>>宏任务 Event-Loop、宏任务、微任务到底是个啥?

那就先到这里吧,站在大佬的肩膀上产出的一篇文章,方便自己学习,如果能帮到他人,那就更好了。

参考:www.bilibili.com/video/BV1Si…