首页IT科技vue的nexttick原理(Vue中$nextTick实现源码解析)

vue的nexttick原理(Vue中$nextTick实现源码解析)

时间2025-09-18 21:46:15分类IT科技浏览5988
导读:正文 先看一个简单的问题...

正文

先看一个简单的问题

<template> <div @click="handleClick" ref="div">{{ text }}</div </template> <script> export default { data() { return { text: old } }, methods: { handleClick() { this.text = new console.log(this.$refs.div.innerText) } } } </script>

此时打印的结果是什么呢?是 old                。如果想让它打印 new                ,使用 nextTick 稍加改造就可以

this.$nextTick(() => { console.log(this.$refs.div.innerText) })

内部实现

但是你想过它内部是怎么实现的么                        ,和我们写 setTimeout 有什么区别呢?

因为平时工作使用的是Vue2        ,所以我就以Vue2的最新版本2.6.14为例进行分析            ,Vue3的实现应该也是大同小异                        。

源码地址:github.com/vuejs/vue/b…

为了方便阅读我删掉了注释                        ,只关注最重要的实现

if (typeof Promise !== undefined && isNative(Promise)) { const p = Promise.resolve() timerFunc = () => { p.then(flushCallbacks) if (isIOS) setTimeout(noop) } isUsingMicroTask = true } else if (!isIE && typeof MutationObserver !== undefined && ( isNative(MutationObserver) || MutationObserver.toString() === [object MutationObserverConstructor] )) { let counter = 1 const observer = new MutationObserver(flushCallbacks) const textNode = document.createTextNode(String(counter)) observer.observe(textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 textNode.data = String(counter) } isUsingMicroTask = true } else if (typeof setImmediate !== undefined && isNative(setImmediate)) { timerFunc = () => { setImmediate(flushCallbacks) } } else { timerFunc = () => { setTimeout(flushCallbacks, 0) } }

先大概扫一遍可知 $nextTick 主要是通过微任务来实现的            ,其实在2.5版本中        ,是采用宏任务与微任务相结合的方式实现的                        ,但因为在渲染和事件处理中一些比较怪异的行为(感兴趣的话可以看下issue)                ,所以最终统一采用了微任务        。

先看第一块:
if (typeof Promise !== undefined && isNative(Promise)) { const p = Promise.resolve() timerFunc = () => { p.then(flushCallbacks) if (isIOS) setTimeout(noop) } isUsingMicroTask = true }

如果可以使用 Promise     ,就采用 promise.then 的方式去执行回调                        ,将任务在下一个tick执行            。但是其中 if (isIOS) setTimeout(noop) 这句话是在做什么呢?在iOS >= 9.3.3的UIWebView中                    ,定义的回调函数通过 Promise 的方式推到微任务队列后,队列不刷新                    ,需要靠 setTimeout 来强制更新一下                        ,noop 就是一个空函数                        。

再看第二块:
else if (!isIE && typeof MutationObserver !== undefined && ( isNative(MutationObserver) || MutationObserver.toString() === [object MutationObserverConstructor] )) { let counter = 1 const observer = new MutationObserver(flushCallbacks) const textNode = document.createTextNode(String(counter)) observer.observe(textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 textNode.data = String(counter) } isUsingMicroTask = true }

如果不能用 Promise 就降级使用 MutationObserver            。创建了一个文本节点    ,并通过 observer 去观察文本节点的变化        。 characterData: true 这个配置就是当文字变化的时候就会执行回调                        。(counter + 1) % 2 会使文本节点的文字在 0                 、 1                         、 0        、 1之间不同变化                ,这样就会被 observer 观察到                。MutationObserver 也是微任务    。

然后是第三块:
else if (typeof setImmediate !== undefined && isNative(setImmediate)) { timerFunc = () => { setImmediate(flushCallbacks) } }

当微任务都不被支持时                        ,就要使用宏任务了                        。其实大多数情况下都不会走到这里        ,因为 setImmediate 并没有成为正式的标准            ,并且兼容性很差                    。

最后是第四块:
else { timerFunc = () => { setTimeout(flushCallbacks, 0) } }

最后在所有方案都行不通时                        ,只能采用 setTimeout 的方式。之所以有第三块是因为虽然都是宏任务            ,但是 setImmediate 会比 setTimeout 快        ,所以MDN上才会说 setTimeout(fn, 0) 不能成为 setImmediate 的polyfill                    。就像作者在注释中写的那样:它仍然是比 setTimeout 更好的选择                        。

一步一步分析了 $nextTick 源码后                        ,你是否对它的用法理解更加透彻了呢?

以上就是Vue中$nextTick实现源码解析的详细内容                ,更多关于Vue $nextTick解析的资料请关注本站其它相关文章!

声明:本站所有文章    ,如无特殊说明或标注                        ,均为本站原创发布    。任何个人或组织                    ,在未征得本站同意时,禁止复制            、盗用                        、采集            、发布本站内容到任何网站        、书籍等各类媒体平台                。如若本站内容侵犯了原著者的合法权益                    ,可联系我们进行处理                        。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
网站一键生成器(轻松搭建个性化网站的利器——网站生成器)