Event-Loop、宏任务、微任务到底是个啥?
我报名参加金石计划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引擎:
Brower:浏览器
call Stack:调用栈,所有JS代码都要先放到调用栈,才能被依次执行
webAPIs:可以理解为JS引擎中处理BOM、DOM节点、事件监听、回调函数等等的一种标准和规范。
callback Queue:顾名思义就是回调队列
Event-Loop:事件循环或者轮询,这里可以理解为同步回调队列与调用栈的一通信机制
在代码被编译执行的时候,是被一并送到调用栈中的,所以最初的调用栈是这样的:
接下来就是依次执行,先打印Hello World,调用栈遇到异步函数,发现它有一个回调函数fun1,此时将回调函数fun1,放到web APIs,等时间到达定时函数规定的时间,便把fun1推送到回调队列中(callback Queue),当call Stack中的同步代码执行完毕之后,call Stack 为空,再基于事件循环,也就是Event Loop机制,轮询callback Queue,发现有fun1,便再次推送到调用栈中,具体如下图所示:
又回到调用栈,按照同步代码依次执行的原理,再执行fun1,打印“Timer1”:
这也正好印证了,为什么即便是定时器设置了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渲染>>宏任务
那就先到这里吧,站在大佬的肩膀上产出的一篇文章,方便自己学习,如果能帮到他人,那就更好了。
转载自:https://juejin.cn/post/7144631166325227534