nextTick原理
用法:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
触发时机:在同一事件循环中的数据变化后,DOM 完成更新,立即执行 Vue.nextTick()的回调。
执行顺序:同一事件循环中的代码执行完毕 -> DOM 更新 -> nextTick callback 触发
应用场景:需要在视图更新之后,基于新的视图进行操作。
异步说明:Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。
事件循环:Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。
# 原理
- vue 用异步队列的方式来控制 DOM 更新和 nextTick 回调先后执行
# 源码分析
nextTick 源码主要分为两块:
把回调函数放入 callbacks 等待执行
能力检测,根据能力检测以不同方式执行回调队列(降级处理)
Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。
宏任务耗费的时间是大于微任务的,所以在浏览器支持的情况下,优先使用微任务。如果浏览器不支持微任务,使用宏任务;但是,各种宏任务之间也有效率的不同,需要根据浏览器的支持情况,使用不同的宏任务。
将执行函数放到微任务或者宏任务中,事件循环到了微任务或者宏任务,执行函数依次执行 callbacks 中的回调
(执行的优先顺序为 promise.then => MutationObserver => setImmediate => setTimeout)
源码解析:
callbacks 用来存储所有需要执行的回调函数
pending 用来标志是否正在执行回调函数
timerFunc 用来触发执行回调函数
# 用法
语法:Vue.nextTick([callback, context])
或者vm.$nextTick([callback]);
参数:
{Function} [callback]
:回调函数,不传时提供 promise 调用{Object} [context]
回调函数执行的上下文环境,不传默认是自动绑定到调用它的实例上。
Vue.nextTick([callback, context]);
该方法是全局方法,该方法可接收 2 个参数,分别为回调函数 和 执行回调函数的上下文环境。
vm.$nextTick([callback])
该方法是实列方法,执行时自动绑定 this 到当前的实列上。
Vue 实例方法vm.$nextTick
做了进一步封装,把 context 参数设置成当前 Vue 实例。
# 应用场景
更改数据后,进行节点 DOM 操作。
在 created 生命周期中进行 DOM 操作。
# MutationObserver
MutationObserver 是 HTML5 中的新 API,是个用来监视 DOM 变动的接口
能监听一个 DOM 对象上发生的子节点删除、属性修改、文本内容修改等等。
兼容性:IE11 及以上
语法:var observer = new MutationObserver(callback);
实例方法:
- observe(target, config) 指定所要观察的 DOM 元素,以及要观察的特定变动。
target:dom 观察目标
disconnect 用来停止观察。发生相应变动时,不再调用回调函数。
takeRecord 用来清除变动记录,即不再处理未处理的变动。
特点:
它等待所有脚本任务完成后,才会运行,即采用异步方式
它把 DOM 变动记录封装成一个数组进行处理,而不是一条条地个别处理 DOM 变动。
它即可以观察发生在 DOM 节点的所有变动,也可以观察某一类变动
参考:https://segmentfault.com/a/1190000012861862 (opens new window)