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

简介: 宏任务(macroTask)和微任务(microTask),都是JavaScript中异步中的一些概念,如果你对其还一头雾水,那就跟着我在捋一遍,加深一下印象。
大家好,我是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应该是这样:

image.png

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

提问

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

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

结束啦

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

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

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

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

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

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

我们下期再见👋

相关文章
|
6月前
|
消息中间件 前端开发 Java
美团面试:如何实现线程任务编排?
线程任务编排指的是对多个线程任务按照一定的逻辑顺序或条件进行组织和安排,以实现协同工作、顺序执行或并行执行的一种机制。 ## 1.线程任务编排 VS 线程通讯 有同学可能会想:那线程的任务编排是不是问的就是线程间通讯啊? 线程间通讯我知道了,它的实现方式总共有以下几种方式: 1. Object 类下的 wait()、notify() 和 notifyAll() 方法; 2. Condition 类下的 await()、signal() 和 signalAll() 方法; 3. LockSupport 类下的 park() 和 unpark() 方法。 但是,**线程通讯和线程的任务编排是
66 1
|
1月前
|
NoSQL Java API
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴在面试一线互联网企业时遇到了关于Redis分布式锁过期及自动续期的问题。尼恩对此进行了系统化的梳理,介绍了两种核心解决方案:一是通过增加版本号实现乐观锁,二是利用watch dog自动续期机制。后者通过后台线程定期检查锁的状态并在必要时延长锁的过期时间,确保锁不会因超时而意外释放。尼恩还分享了详细的代码实现和原理分析,帮助读者深入理解并掌握这些技术点,以便在面试中自信应对相关问题。更多技术细节和面试准备资料可在尼恩的技术文章和《尼恩Java面试宝典》中获取。
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
|
1月前
|
存储
经典面试题:写一个"标准"宏MIN ,这个宏输入两个参数并返回较小的一个 复制 #define MIN(a,b) ((a)<=(b)?(a):(b))
你的宏定义已非常接近标准。以下是改进后的 `MIN` 宏定义,支持多种数据类型并避免副作用:
|
1月前
|
Android开发 Kotlin
Android面试题之Kotlin中如何实现串行和并行任务?
本文介绍了 Kotlin 中 `async` 和 `await` 在并发编程中的应用,包括并行与串行任务的处理方法。并通过示例代码展示了如何启动并收集异步任务的结果。
25 0
|
4月前
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
78 1
|
5月前
|
消息中间件 算法 Java
抖音面试:说说延迟任务的调度算法?
Netty 框架是以性能著称的框架,因此在它的框架中使用了大量提升性能的机制,例如 Netty 用于实现延迟队列的时间轮调度算法就是一个典型的例子。使用时间轮调度算法可以实现海量任务新增和取消任务的时间度为 O(1),那么什么是时间轮调度算法呢?接下来我们一起来看。 ## 1.延迟任务实现 在 Netty 中,我们需要使用 HashedWheelTimer 类来实现延迟任务,例如以下代码: ```java public class DelayTaskExample { public static void main(String[] args) { System.ou
53 5
抖音面试:说说延迟任务的调度算法?
|
4月前
|
设计模式 安全 Java
Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
63 0
|
4月前
|
设计模式 SQL 安全
Java面试题:设计一个线程安全的内存管理器,使用观察者模式来通知所有线程内存使用情况的变化。如何确保在添加和移除内存块时的线程安全?如何确保任务的顺序执行和调度器的线程安全?
Java面试题:设计一个线程安全的内存管理器,使用观察者模式来通知所有线程内存使用情况的变化。如何确保在添加和移除内存块时的线程安全?如何确保任务的顺序执行和调度器的线程安全?
38 0
|
4月前
|
设计模式 并行计算 安全
Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
50 0
|
4月前
|
存储 安全 Java
Java面试题:如何在Java应用中实现有效的内存优化?在多线程环境下,如何确保数据的线程安全?如何设计并实现一个基于ExecutorService的任务处理流程?
Java面试题:如何在Java应用中实现有效的内存优化?在多线程环境下,如何确保数据的线程安全?如何设计并实现一个基于ExecutorService的任务处理流程?
46 0