与事情循环相关的微任务与宏任务

    随着浏览器的应用领域越来越广泛,消息队列中这种粗时间颗粒度的任务已经不能胜任部分领域的需求,所以又出现了一种新的技术——微任务。微任务可以在实时性效率之间做一个有效的权衡。基于微任务的技术有 MutationObserverPromise 以及以 Promise 为基础开发出来的很多其他的技术。

宏任务

    页面中的大部分任务都是在主线程上执行的,这些任务包括了:渲染事件(如解析 DOM、计算布局、绘制);用户交互事件(如鼠标点击、滚动页面、放大缩小等);JavaScript 脚本执行事件网络请求完成文件读写完成事件。(PS:以上是WHATWG标准定义的。但是在浏览器实现的过程中,目前只有一个消息队列,和一个延迟执行队列。一个是规范,一个是实现)
    为了协调这些任务有条不紊地在主线程上执行,页面进程引入了消息队列和事件循环机制,渲染进程内部会维护多个消息队列,比如延迟执行队列和普通的消息队列。然后主线程采用一个 for 循环,不断地从这些任务队列中取出任务并执行任务。我们把这些消息队列中的任务称为宏任务
    消息队列中的任务是通过事件循环系统来执行的。大致流程如下:
    先从多个消息队列中选出一个最老的任务,这个任务称为 oldestTask;然后循环系统记录任务开始执行的时间,并把这个 oldestTask 设置为当前正在执行的任务;当任务执行完成之后,删除当前正在执行的任务,并从对应的消息队列中删除掉这个 oldestTask;最后统计执行完成的时长等信息。
    宏任务可以满足我们大部分的日常需求,不过如果有对时间精度要求较高的需求,宏任务就难以胜任了。

微任务

异步回调主要有两种方式
    第一种是把异步回调函数封装成一个宏任务添加到消息队列尾部,当循环系统执行到该任务的时候执行回调函数。setTimeoutXMLHttpRequest 的回调函数都是通过这种方式来实现的。
    第二种方式的执行时机是在主函数执行结束之后、当前宏任务结束之前执行回调函数,这通常都是以微任务形式体现的。那这里说的微任务到底是什么呢?微任务就是一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前。

    要搞清楚微任务系统是怎么运转起来的,就得站在 V8 引擎的层面来分析下。
    当 JavaScript 执行一段脚本的时候,V8 会为其创建一个全局执行上下文,在创建全局执行上下文的同时,V8 引擎也会在内部创建一个微任务队列。顾名思义,这个微任务队列就是用来存放微任务的,因为在当前宏任务执行的过程中,有时候会产生多个微任务,这时候就需要使用这个微任务队列来保存这些微任务了。不过这个微任务队列是给 V8 引擎内部使用的,所以你是无法通过 JavaScript 直接访问的。也就是说每个宏任务都关联了一个微任务队列。

在现代浏览器里面,产生微任务有两种方式
    第一种方式是使用 MutationObserver 监控某个 DOM 节点,然后再通过 JavaScript修改这个节点,或者为这个节点添加删除部分子节点,当 DOM 节点发生变化时,就会产生 DOM 变化记录的微任务。
    第二种方式是使用 Promise,当调用 Promise.resolve() 或者 Promise.reject() 的时候,也会产生微任务。

    在当前宏任务中的 JavaScript 快执行完成时,也就在 JavaScript 引擎准备退出全局执行上下文并清空调用栈的时候,JavaScript 引擎会检查全局执行上下文中的微任务队列,然后按照顺序执行队列中的微任务。WHATWG 把执行微任务的时间点称为检查点。当然除了在退出全局执行上下文式这个检查点之外,还有其他的检查点,不过不是太重要,就不做介绍了。
    如果在执行微任务的过程中,产生了新的微任务,同样会将该微任务添加到微任务队列中,V8 引擎一直循环执行微任务队列中的任务,直到队列为空才算执行结束。也就是说在执行微任务过程中产生的新的微任务并不会推迟到下个宏任务中执行,而是在当前的宏任务中继续执行。

可以得出如下几个结论:
    微任务和宏任务是绑定的,每个宏任务在执行时,会创建自己的微任务队列。
    微任务的执行时长会影响到当前宏任务的时长。比如一个宏任务在执行过程中,产生了 100 个微任务,执行每个微任务的时间是 10 毫秒,那么执行这 100 个微任务的时间就是 1000 毫秒,也可以说这 100 个微任务让宏任务的执行时间延长了 1000 毫秒。所以你在写代码的时候一定要注意控制微任务的执行时长。
    在一个宏任务中,分别创建一个用于回调的宏任务和微任务,无论什么情况下,微任务都早于宏任务执行。

监听 DOM 变化方法演变

    MutationObserver 是用来监听 DOM 变化的一套方法,而监听 DOM 变化一直是前端工程师一项非常核心的需求。
    MutationObserver 采用了“异步 + 微任务”的策略。通过异步操作解决了同步操作的性能问题,通过微任务解决了实时性的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值