「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战」
nextTick
首先先让我们回顾一下:异步更新队列-nextTick()
-
Vue 更新 Dom 是异步执行的,批量的
- 在下次 DOM 更新循环结束之后执行延迟回调。再修改数据之后立即使用这个方法,获取更新后的DOM。
-
vm.$nextTick(function() {/*操作DOM}*/ })/Vue.nextTick(function(){}) -
静态方法 nextTick
- 路径: src\core\global-api\index.js
// 静态方法 nextTick Vue.nextTick = nextTick
- 路径: src\core\global-api\index.js
-
实例方法 nextTick
- 路径:src\core\instance\index.js
// 混入 render // $nextTick/_render renderMixin(Vue) - renderMixin
Vue.prototype.$nextTick = function (fn: Function) { return nextTick(fn, this) }
- 路径:src\core\instance\index.js
对比两个方法我们发现最终调用的都是nextTick这个方法,也就是说其实我们只需要研究nextTick就好了,e。。。。有点绕哈,其实就是src\core\util\next-tick.js下的nextTick函数就是了
nextTick
参数:
- cb?: Function - 可选参数,回调函数
- ctx?: Object - 上下文,一般就是 vue 实例
- 把 cb 加上异常处理存入 callbacks 数组中,所有用户传入的函数,
Vue认为都是危险的,都会给我们加上try/catch(严谨啊!)
callbacks.push(() => {
if (cb) {
try {
// 调用 cb()
cb.call(ctx)
} catch (e) {
handleError(e, ctx, 'nextTick')
}
} else if (_resolve) {
_resolve(ctx)
}
})
- 判断队列是否被处理,如果队列没有被处理,会设置
pending为true表示队列为正在处理中
if (!pending) {
pending = true
// 调用
timerFunc()
}
timerFunc:我们可以看见,这个函数中调用了 Promise,调用flushCallbacks函数const p = Promise.resolve() timerFunc = () => { p.then(flushCallbacks) if (isIOS) setTimeout(noop) }flushCallbacks:设置函数已经执行结束,并且复制一次callbacks数组后清空,遍历回调函数并执行。在浏览器不执行function flushCallbacks () { pending = false const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } }MutationObserver、Promise时候,会降级成setImmediate(小知识:setImmediate的性能大于setTimeout哦!我们在设置setTimeout时延迟设置为0也会等待4毫秒,setImmediate则会立即执行)
小结
nextTick 异步更新队列 处理的时候
- 1、先将回调函数放入
callbacks数组中,优先以微任务的形式执行微任务,如果浏览器不支持的话会降级成宏任务的形式