JavaScript——微任务&宏任务

585 阅读3分钟

这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战

前言

关于执行顺序这一块,大多文章已经讲的非常通俗易懂(我会放置几篇我认为较好的文章链接在文末),所以关于执行顺序的阐述是比较简明扼要的,想要详细理解执行顺序可以直接移步至文末,本文主要通过这道题来帮助大家真正理解执行顺序并运用。如有错误,希望能指正一下,拜托了。

最近在复习fetch的时候偶然遇见一道面试题,紧接着由这道题引出了一道关于微任务和宏任务执行顺序的面试题

function log3() {
    Promise.resolve().then(() => {
        log3();
    })
}
log3();
function log2() {
    setTimeout(log2);
}
log2();

分别执行这两段代码,看看有什么差别,为什么会有这样的差别?(第一段浏览器会“卡住”,第二段不会)

遇到这道题想看解析但没有,于是只能自己研究,在查看了数篇博客之后苦思冥想不得其解,在上厕所的时候突然想明白了,在这里就拿出来给大家唠一唠。

宏任务与任务的执行顺序

JavaScript是一个单进程的语言,同一时间不能处理多个任务,所以何时执行宏任务,何时执行微任务?我们需要有这样的一个判断逻辑存在。

一个宏任务执行完毕后会检查同一层级是否还有微任务没有处理(对于层级这个名词不理解的可以配合文末第一个链接食用),若有则处理,否则结束本次宏任务然后检查还有没有宏任务需要处理,如此循环也就变成了我们耳熟能详的事件循环机制(Event-Loop)

宏任务与微任务

明白了执行顺序,你还要能分清楚哪些是宏任务哪些是微任务

  • 宏任务一般是:整体代码scriptI/OsetTimeoutsetIntervalsetImmediate。(这里小提一嘴,ajax也算是宏任务)

  • 微任务一般是:原生Promise(有些实现的promise将then方法放到了宏任务中)、process.nextTick、Object.observe(已废弃)、 MutationObserver 记住就行了。

自己可以验证一下,或者随便找道面试题来为难自己(狗头保命)

回到题目

function log3() {
    Promise.resolve().then(() => {
        log3();
    })
}
log3();

这里我带着大家一步一步往下顺

  1. 首先执行script代码
  2. 然后执行微任务.then(() => {log3();})
  3. 循环进行第二步 然后浏览器卡死,无法进行鼠标右击或者其它操作。很容易发现,这里每一次循环都是同一层级的微任务的执行,而回到我刚才说过的循环机制

一个宏任务执行完毕后会检查同一层级是否还有微任务没有处理,若有则处理,否则结束本次宏任务然后检查还有没有宏任务需要处理

也就是说这个我们要处理完所有这一层级的微任务之后才能去处理宏任务。 这也就导致了我们的鼠标右键(I/O)等宏任务无法正常执行。所以就出现了浏览器“卡死”的状况

function log2() {
    setTimeout(log2);
}
log2();

而这段代码,就是一个宏任务的无限递归调用,而宏任务并不会阻塞宏任务,所以在这个时候我们可以正常的执行鼠标右键和鼠标左键等宏任务事件。

大家可以自己在控制台里加入一点宏任务运行试一试。

最后

最近挺烦的,早就想写点东西,一直都找不到写什么,主要还是自己太菜。

文章链接:

这次,十分钟把宏任务和微任务讲清楚 (juejin.cn)(这个文章解释了一下层级的概念,没有理解的同学可以自行食用)

宏任务与微任务(此文章对于事件循环讲的很详细到位,想深究的同学可以自行食用)