微任务到底是什么?
微任务就是一个需要异步执行的函数,执行时机是在主函数执行结束之后,当前宏任务结束之前。
微任务有什么用?
微任务可以在实时性和效率之间做一个有效的权衡。
基于微任务的技术有哪些?
MutationObserver、Promise 以及以 Promise 为基础开发出来的很多其他的技术。
宏任务有哪些?
凡是在主线程上执行的任务都是宏任务。包括:
-
渲染事件(如解析 DOM、计算布局、绘制);
-
用户交互事件(如鼠标点击、滚动页面、放大缩小等);
-
JavaScript 脚本执行事件;
-
网络请求完成、文件读写完成事件。
WHATWG规范中是如何定义事件循环机制的?
先从多个消息队列中选出一个最老的任务,这个任务称为 oldestTask;
然后循环系统记录任务开始执行的时间,并把这个 oldestTask 设置为当前正在执行的任务;
当任务执行完成之后,删除当前正在执行的任务,并从对应的消息队列中删除掉这个oldestTask;
最后统计执行完成的时长等信息。
为什么宏任务难以满足对时间精度要求较高的任务?
因为页面的渲染事件、各种IO的完成事件、执行JavaScript脚本的事件、用户交互的事件等都随时有可能被添加到消息队列中,而且添加事件是由系统操作的,JavaScript代码不能准确掌控任务要添加到队列中的位置,控制不了任务在消息队列中的位置,所以很难控制开始执行任务的时间。setTimeout函数触发的回调函数都是宏任务,如图所示:一旦中间插入别的任务,就会影响后面任务的执行。
![image-20201028143424051](/Users/zhoupanpan/Library/Application Support/typora-user-images/image-20201028143424051.png)
微任务是如何产生的?给谁使用?
当JavaScript执行一段脚本时,V8会为其创建一个全局执行上下文,创建的同时,V8也会在内部创建一个微任务队列用来存放微任务。
微任务队列是给V8引擎内部使用的,无法通过JavaScript直接访问。
微任务如何产生?
-
使用 MutationObserver 监控某个 DOM 节点,然后再通过 JavaScript 来修改这个节点,或者为这个节点添加、删除部分子节点,当 DOM 节点发生变化时,就会产生 DOM 变化记录的微任务
-
使用 Promise,当调用 Promise.resolve() 或者 Promise.reject() 的时候,也会产生微任务
微任务队列何时被执行?
在当前宏任务中的 JavaScript 快执行完成时,也就在 JavaScript 引擎准备退出全局执行上下文并清空调用栈的时候,JavaScript 引擎会检查全局执行上下文中的微任务队列,然后按照顺序执行队列中的微任务。WHATWG 把执行微任务的时间点称为检查点。
关于微任务的结论有哪些?
- 微任务和宏任务是绑定的,每个宏任务在执行时,会创建自己的微任务队列。
- 微任务的执行时长会影响到当前宏任务的执行时长。因此写代码时要注意控制微任务的执行时长
- 在一个宏任务中,分别创建一个用于回调的宏任务和微任务,无论什么情况下,微任务都早于宏任务执行
监听DOM变化技术方案的演化史是怎样的?
- 轮询检测
方式:使用setTimeout和setinterval来定时检测DOM是否有改变
问题:1、如果时间间隔设置过长,DOM变化响应不够及时;2、果果时间间隔设置过短,会浪费很多无用的工作量去检查DOM,会让页面变得低效。
- Mutation Even
方式:采用了观察者的设计模式,当DOM有变动就会立刻触发相应的事件,这种方式属于同步回调。
优点:解决了实时性的问题。因为 DOM 一旦发生变化,就会立即调用JavaScript 接口
缺点:但也正是这种实时性引发了严重的性能问题,导致动画卡顿等。
- MutationObserver
1、如何缓解性能问题?
将响应函数改成异步调用,等多次DOM变化后,一次触发异步调用,而非每次调用。并且使用一个数据结构来记录期间所有的DOM变化,以此减少对性能的影响。
2、如何保持消息通知的及时性?
通过微任务。每次DOM节点发生变化的时候,渲染引擎将变化记录封装成微任务,并将微任务添加进当前的微任务队列中。这样当执行到检查点的时候,V8引擎就会按照顺序执行微任务了。
综上所述: MutationObserver 采用了“异步 + 微任务”的策略。
通过异步操作解决了同步操作的性能问题
通过微任务解决了实时性的问题