写点什么

面试官:对于宏任务和微任务,你知道多少?

  • 2022 年 3 月 10 日
  • 本文字数:2361 字

    阅读完需:约 8 分钟

面试官:对于宏任务和微任务,你知道多少?

大家好,我是 Ned👀,一个刚刚入门前端未满两年的大三小学生🌹

未来路还长🎉, 一起努力加油吧❤~


欢迎小伙伴们持续关注我的公众号:前端成长日记

前言

宏任务(macroTask)和微任务(microTask),都是 JavaScript 中异步中的一些概念,如果你对其还一头雾水,那就跟着我在捋一遍,加深一下印象。


老规矩,先上图:



梳理这块主要还是为了让自己对代码执行的逻辑能够更加的清晰,当然,某些原因的还是应对一些面试题。

什么是宏任务,什么是微任务?

我们来以题入手,这应该是一道比较常见的题了:


    console.log(100)    setTimeout(()=>{        console.log(200)    })    Promise.resolve().then(()=>{        console.log(300)    })    console.log(400)    // 答案为: 100 400 300 200
复制代码


问的就是,这段代码执行后,打印出来的顺序是什么?如果你心中的结果跟答案不一样的话,不要慌,首先对于同步异步有些了解的可以看出,先打印出 100 400 肯定是没有毛病的了,问题应该就出在 200 跟 300 上,它俩之间 300 为什么要比 200 打印的早呢?


异步跟出场顺序有关系,不同类型的异步跟出场顺序就没关系了


这就是为什么setTimeoutpromise之上,但是 200 却在 300 之后打印出来的原因。假如我在打印 200 的那个setTimeout后立刻跟一个打印 222 的setTimeout,那么在同样的setTimeout之间,打印顺序是由你写的顺序决定的(定时时间记得一致)。


那这个不同类型,就是宏任务和微任务两种了。我们直接来看一看,哪些是宏任务,哪些是微任务:


  • 宏任务:setTimeout,setInterval,Ajax,DOM 事件

  • 微任务:Promise,async/await


微任务的执行时机要比宏任务早!(可以先记一哈,后面会继续说这点)

Dom 事件不是异步操作,但是它依赖了 eventloop 机制,所以也归在这点里了


可以看出,宏任务和微任务组合起来,就是我们说的异步。先直接记住结果,再去探究为什么,看到这里应该可以回头去做出来之前那个题了,setTimeout是个宏任务,而pormise是个微任务,微任务要比宏任务执行的要早,所以先打印出来 300 后打印 200。

eventloop 和 DOM 渲染

eventloop和DOM渲染是与为什么宏任务比微任务执行的晚有联系的,所以我们先来弄懂这个。再举个例子:


    const div1 = $('<div>1234</div>')    const div2 = $('<div>1234</div>')    const div3 = $('<div>1234</div>')    const div4 = $('<div>1234</div>')    const div5 = $('<div>1234</div>')    $('#divs').append(div1).append(div2).append(div3).append(div4).append(div5)    console.log('length', $(divs).children().length) // 5
复制代码


我们用 js 建几个 div,之后添加到一个节点下,再立刻打印一下这个节点下子元素的个数,这几行执行完之后,我们可以看出打印了 5,页面上也显示了五段话,这没有什么问题。


但是我们这里要 get 的一点是,我们的眼睛是在什么时刻看到这五段话的


要了解的一点是:DOM 渲染就是将 DOM 结构或者是 js 操作的内容渲染到浏览器上,让我们的眼睛可以看见。


其实如果只执行这一段 js,到打印那行为止,我们是能打印出来 5 的,但是此时此刻我们是看不见页面上新增的那五段话的。所以我们需要时机去执行这个 DOM 渲染的过程,就要去了解一下 eventloop 的过程。


大概画了一下,在 eventloop 中主要有这么几个东西,我们再详细说一下它。



首先我们知道,js 是单线程了,按照顺序一行一行执行,如果某行报错则停止后续执行,然后就是先执行同步,再执行异步,看图,我们会将同步代码一行一行放入Call Stack中执行,遇到异步,就会移动到Web APIs中记录下来,等待时机,如果时机到了,将其移动到Callback Queue中,如果同步代码执行完,也就是Call Stack为空,这时候首先会尝试 DOM 渲染,之后再触发Event Loop机制Event Loop开始工作,轮询查找Callback Queue,如果有就移动到Call Stack中执行。


请注意:为什么是尝试 DOM 渲染,因为可能这一段 js 里并没有修改 DOM,尝试是代表着如果有对 DOM 的操作,那么去渲染,没有的话,忽略这一步。

为什么宏任务比微任务执行的晚

这段代码接着上面建立的那一堆 DIV 去执行,alert会阻断 js 执行,也会阻断 DOM 渲染,利用这一点,我们可以直观的去看出谁先谁后和 DOM 渲染在什么时候执行的。


    // 微任务:DOM渲染之前执行    Promise.resolve().then(() => {        const length = $('#divs').children().length        alert(`微任务 ${length}`)    })
// 宏任务:DOM渲染之后执行 setTimeout(() => { const length = $('#divs').children().length alert(`宏任务 ${length}`)})
复制代码

宏任务和微任务的区别

还是要从 eventloop 的角度来看,首先我们来看setTimeout



首先要进入Web APIs中等待时机,完后进入Callback Queue中,等待EventLoop机制被触发之后执行,而尝试 DOM 渲染刚刚好,卡在了Call Stack空闲下来,跟执行EventLoop机制中间,这就是为什么setTimeout在 DOM 渲染之后执行的原因


接着我们来看Promise.then



PromiseES6规范的,不是 W3C 规范的所以不经过Web APIs,此外与宏任务不同的一点是,有自己独特的micro task queue,这是为什么呢?


  • 微任务是 ES6 语法规定的

  • 宏任务是由浏览器规定的规定的地方不一样导致存放位置的不一样,所以才有了图中存放位置的不同。


所以最终我们的EventLoop应该是这样:



Call Stack清空之后,首先执行当前的微任务,再去尝试DOM渲染,最后触发EventLoop机制,执行宏任务。

提问

学完了来看看自己会不会吧?


  • 宏任务跟微任务分别有哪些?

  • 为什么微任务的触发时机更早?

  • 微任务宏任务和 DOM 渲染的关系?

  • 微任务宏任务和 DOM 渲染,在 EventLoop 中的过程?

结束啦

宏任务跟微任务是 JavaScript 异步中的一个大块,所以快来学习吧!


梳理好每一个知识点,稳扎稳打,才不会被面试官问倒😰~


如果文章有误欢迎在评论区指出,感谢指正🔔


如果您觉得以上的内容还不错,不妨点个赞支持一下哦~~😇


我们下期再见👋

发布于: 2022 年 03 月 10 日阅读数: 111
用户头像

还未添加个人签名 2021.08.09 加入

还未添加个人简介

评论

发布
暂无评论
面试官:对于宏任务和微任务,你知道多少?_JavaScript_是乃德也是Ned_InfoQ写作平台