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

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

时间2025-06-14 07:09:36分类IT科技浏览4434
导读:正文 先看一个简单的问题...

正文

先看一个简单的问题

<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
seo网站优化如何做(seo网站优化方法) pytorch(Pytorch DataLoader中的num_workers (选择最合适的num_workers值))