Vue 源码学习 (5) - nextTick

发布于 2023-11-26 18:06:52 字数 1564 浏览 33 评论 0

写在前面

在平时开发中,我们更新数据后,需要通过 nextTick 的回调中才能获取 DOM。

this.value = 1
this.$nextTick(() => {
	...
})

通过前面的文章我们知道,这是因为 Vue 中数据更新后,视图并不是立即更新,而是进入批量更新的队列中,而批量更新的队列也是在 nextTick 的回调,所以当 更新的回调执行完成后,我们操作 dom 的回调执行时才能正确获取到 DOM 的状态。

所以来看看 nextTick

nextTick

export function nextTick(cb?: (...args: any[]) => any, ctx?: object) {
	let _resolve
	callbacks.push(() => {
		if (cb) {
		cb.call(ctx)
		} else if (_resolve) {
		_resolve(ctx)
		}

	})
	if (!pending) {
		pending = true
		timerFunc()
	}
	if (!cb && typeof Promise !== 'undefined') {
	return new Promise(resolve => {
		_resolve = resolve
	})

	}

}

nextTick 方法可以将 回调函数推入到 callbacks 数组中,如果未传入 cb, 则会执行 resolve, 保证 nextTick 后的 then 回调被执行。

这里会执行 timeFunc 函数

const p = Promise.resolve()
timerFunc = () => {
	p.then(flushCallbacks)
	if (isIOS) setTimeout(noop)
}
...
timerFunc = () => {
	setImmediate(flushCallbacks)
}
...
timerFunc = () => {
	setTimeout(flushCallbacks, 0)
}

这里做了很多兼容,有使用 Promise 的微任务回调版本,也有定时器版本的宏任务版本。

这里保证 nextTick 回调的执行实际在 任务队列中完成,执行 flushCallbacks

function flushCallbacks() {
	pending = false
	const copies = callbacks.slice(0)
	callbacks.length = 0
	for (let i = 0; i < copies.length; i++) {
		copies[i]()
	}
}

平时我们使用的 $nextTick 就是 这个逻辑

Vue.nextTick = nextTick
Vue.prototype.$nextTick = function (fn: (...args: any[]) => any) {
	return nextTick(fn, this)
}

总结

通过对 nextTick 的源码学习,我们知道了 Vue 的批量更新是 不是在主线程执行的逻辑里面,而是在任务队列中执行相关的逻辑。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

十秒萌定你

暂无简介

文章
评论
26 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文