Vue中$nextTick實(shí)現(xiàn)源碼解析
正文

先看一個(gè)簡(jiǎn)單的問(wèn)題
<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>
此時(shí)打印的結(jié)果是什么呢?是 'old'。如果想讓它打印 'new',使用 nextTick 稍加改造就可以
this.$nextTick(() => {
console.log(this.$refs.div.innerText)
})
內(nèi)部實(shí)現(xiàn)
但是你想過(guò)它內(nèi)部是怎么實(shí)現(xiàn)的么,和我們寫(xiě) setTimeout 有什么區(qū)別呢?
因?yàn)槠綍r(shí)工作使用的是Vue2,所以我就以Vue2的最新版本2.6.14為例進(jìn)行分析,Vue3的實(shí)現(xiàn)應(yīng)該也是大同小異。
為了方便閱讀我刪掉了注釋?zhuān)魂P(guān)注最重要的實(shí)現(xiàn)
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 主要是通過(guò)微任務(wù)來(lái)實(shí)現(xiàn)的,其實(shí)在2.5版本中,是采用宏任務(wù)與微任務(wù)相結(jié)合的方式實(shí)現(xiàn)的,但因?yàn)樵阡秩竞褪录幚碇幸恍┍容^怪異的行為(感興趣的話可以看下issue),所以最終統(tǒng)一采用了微任務(wù)。
先看第一塊:
if (typeof Promise !== 'undefined' && isNative(Promise)) {
const p = Promise.resolve()
timerFunc = () => {
p.then(flushCallbacks)
if (isIOS) setTimeout(noop)
}
isUsingMicroTask = true
}
如果可以使用 Promise ,就采用 promise.then 的方式去執(zhí)行回調(diào),將任務(wù)在下一個(gè)tick執(zhí)行。但是其中 if (isIOS) setTimeout(noop) 這句話是在做什么呢?在iOS >= 9.3.3的UIWebView中,定義的回調(diào)函數(shù)通過(guò) Promise 的方式推到微任務(wù)隊(duì)列后,隊(duì)列不刷新,需要靠 setTimeout 來(lái)強(qiáng)制更新一下,noop 就是一個(gè)空函數(shù)。
再看第二塊:
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 就降級(jí)使用 MutationObserver。創(chuàng)建了一個(gè)文本節(jié)點(diǎn),并通過(guò) observer 去觀察文本節(jié)點(diǎn)的變化。 characterData: true 這個(gè)配置就是當(dāng)文字變化的時(shí)候就會(huì)執(zhí)行回調(diào)。(counter + 1) % 2 會(huì)使文本節(jié)點(diǎn)的文字在 0 、 1 、 0 、 1之間不同變化,這樣就會(huì)被 observer 觀察到。MutationObserver 也是微任務(wù)。
然后是第三塊:
else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
timerFunc = () => {
setImmediate(flushCallbacks)
}
}
當(dāng)微任務(wù)都不被支持時(shí),就要使用宏任務(wù)了。其實(shí)大多數(shù)情況下都不會(huì)走到這里,因?yàn)?setImmediate 并沒(méi)有成為正式的標(biāo)準(zhǔn),并且兼容性很差。
最后是第四塊:
else {
timerFunc = () => {
setTimeout(flushCallbacks, 0)
}
}
最后在所有方案都行不通時(shí),只能采用 setTimeout 的方式。之所以有第三塊是因?yàn)殡m然都是宏任務(wù),但是 setImmediate 會(huì)比 setTimeout 快,所以MDN上才會(huì)說(shuō) setTimeout(fn, 0) 不能成為 setImmediate 的polyfill。就像作者在注釋中寫(xiě)的那樣:它仍然是比 setTimeout 更好的選擇。
一步一步分析了 $nextTick 源碼后,你是否對(duì)它的用法理解更加透徹了呢?
以上就是Vue中$nextTick實(shí)現(xiàn)源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Vue $nextTick解析的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue項(xiàng)目啟動(dòng)端口更改的實(shí)現(xiàn)
在Vue前端項(xiàng)目中,可以通過(guò)修改配置文件來(lái)指定啟動(dòng)的端口號(hào),本文就來(lái)介紹 一下vue項(xiàng)目啟動(dòng)端口更改的實(shí)現(xiàn),感興趣的可以了解一下2023-10-10
基于vue3與supabase系統(tǒng)認(rèn)證機(jī)制詳解
這篇文章主要介紹了基于vue3與supabase系統(tǒng)認(rèn)證機(jī)制,,系統(tǒng)使用基于 JWT (JSON Web Token) 的認(rèn)證方式,提供了安全可靠的用戶身份管理機(jī)制,需要的朋友可以參考下2025-04-04
Vue動(dòng)畫(huà)之第三方類(lèi)庫(kù)實(shí)現(xiàn)動(dòng)畫(huà)方式
這篇文章主要介紹了Vue動(dòng)畫(huà)之第三方類(lèi)庫(kù)實(shí)現(xiàn)動(dòng)畫(huà)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
vue3配置代理實(shí)現(xiàn)axios請(qǐng)求本地接口返回PG庫(kù)數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了vue3配置代理實(shí)現(xiàn)axios請(qǐng)求本地接口返回PG庫(kù)數(shù)據(jù)的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2025-03-03

