6

对于宏任务和微任务,你知道多少?

 2 years ago
source link: https://juejin.cn/post/7064596910878752804
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

「2022 年什么会火?什么该学?本文正在参与“聊聊 2022 技术趋势”征文活动 」

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

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

欢迎小伙伴们持续关注我的面试专栏,地址:Ned的面试加油站

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

老规矩,先上图:

image.png

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

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

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

    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中主要有这么几个东西,我们再详细说一下它。

image.png

首先我们知道,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

image.png

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

接着我们来看Promise.then

image.png

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

  • 微任务是ES6语法规定的
  • 宏任务是由浏览器规定的

规定的地方不一样导致存放位置的不一样,所以才有了图中存放位置的不同。

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

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

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

  • 宏任务跟微任务分别有哪些?
  • 为什么微任务的触发时机更早?
  • 微任务宏任务和DOM渲染的关系?
  • 微任务宏任务和DOM渲染,在EventLoop中的过程?

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

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

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

这是我面试专栏的第二篇文章,后续会陆陆续续继续整理的,欢迎大家关注📢

👉专栏地址:Ned的面试加油站👈

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

我们下期再见👋


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK