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

大家好,我是 Ned👀,一个刚刚入门前端未满两年的大三小学生🌹
未来路还长🎉, 一起努力加油吧❤~
欢迎小伙伴们持续关注我的公众号:前端成长日记
前言
宏任务(macroTask)和微任务(microTask),都是 JavaScript 中异步中的一些概念,如果你对其还一头雾水,那就跟着我在捋一遍,加深一下印象。
老规矩,先上图:

梳理这块主要还是为了让自己对代码执行的逻辑能够更加的清晰,当然,某些原因的还是应对一些面试题。
什么是宏任务,什么是微任务?
我们来以题入手,这应该是一道比较常见的题了:
问的就是,这段代码执行后,打印出来的顺序是什么?如果你心中的结果跟答案不一样的话,不要慌,首先对于同步异步有些了解的可以看出,先打印出 100 400 肯定是没有毛病的了,问题应该就出在 200 跟 300 上,它俩之间 300 为什么要比 200 打印的早呢?
异步跟出场顺序有关系,不同类型的异步跟出场顺序就没关系了
这就是为什么setTimeout
在promise
之上,但是 200 却在 300 之后打印出来的原因。假如我在打印 200 的那个setTimeout
后立刻跟一个打印 222 的setTimeout
,那么在同样的setTimeout
之间,打印顺序是由你写的顺序决定的(定时时间记得一致)。
那这个不同类型,就是宏任务和微任务两种了。我们直接来看一看,哪些是宏任务,哪些是微任务:
宏任务:setTimeout,setInterval,Ajax,DOM 事件
微任务:Promise,async/await
微任务的执行时机要比宏任务早!(可以先记一哈,后面会继续说这点)
Dom 事件不是异步操作,但是它依赖了 eventloop 机制,所以也归在这点里了
可以看出,宏任务和微任务组合起来,就是我们说的异步。先直接记住结果,再去探究为什么,看到这里应该可以回头去做出来之前那个题了,setTimeout
是个宏任务,而pormise
是个微任务,微任务要比宏任务执行的要早,所以先打印出来 300 后打印 200。
eventloop 和 DOM 渲染
eventloop和DOM渲染
是与为什么宏任务比微任务执行的晚
有联系的,所以我们先来弄懂这个。再举个例子:
我们用 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 渲染在什么时候执行的。
宏任务和微任务的区别
还是要从 eventloop 的角度来看,首先我们来看setTimeout

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

Promise
是ES6
规范的,不是 W3C 规范的所以不经过Web APIs
,此外与宏任务不同的一点是,有自己独特的micro task queue
,这是为什么呢?
微任务是 ES6 语法规定的
宏任务是由浏览器规定的规定的地方不一样导致存放位置的不一样,所以才有了图中存放位置的不同。
所以最终我们的EventLoop
应该是这样:

当Call Stack
清空之后,首先执行当前的微任务
,再去尝试DOM渲染
,最后触发EventLoop机制
,执行宏任务。
提问
学完了来看看自己会不会吧?
宏任务跟微任务分别有哪些?
为什么微任务的触发时机更早?
微任务宏任务和 DOM 渲染的关系?
微任务宏任务和 DOM 渲染,在 EventLoop 中的过程?
结束啦
宏任务跟微任务是 JavaScript 异步中的一个大块,所以快来学习吧!
梳理好每一个知识点,稳扎稳打,才不会被面试官问倒😰~
如果文章有误欢迎在评论区指出,感谢指正🔔
如果您觉得以上的内容还不错,不妨点个赞支持一下哦~~😇
我们下期再见👋
版权声明: 本文为 InfoQ 作者【是乃德也是Ned】的原创文章。
原文链接:【http://xie.infoq.cn/article/bab9bd204b18bfb2e29216abe】。文章转载请联系作者。
评论