Vue NextTick介紹與使用原理
一、NextTick是什么
定義
在下次 DOM 更新循環(huán)結束之后執(zhí)行延遲回調。在修改數(shù)據(jù)之后立即使用這個方法,獲取更新后的 DOM。
理解
Vue在更新DOM時時異步執(zhí)行的。當數(shù)據(jù)發(fā)生變化時,Vue將開啟一個異步更新隊列,視圖需要等隊列中所有數(shù)據(jù)變化完成之后,再統(tǒng)一進行更新。
舉例:
<body>
<div id="app">
<div>
<button id="firstBtn" @click="testClick()" ref="aa">{{testMsg}}</button>
</div>
</div>
</body>
</html>
<script>
new Vue({
el:'#app',
data () {
return {
testMsg:"原始值",
}
},
methods:{
testClick:function(){
this.testMsg="修改后的值";
console.log(this.$refs.aa.innerText); //that.$refs.aa獲取指定DOM,輸出:原始值
console.log(document.querySelector('#firstBtn').innerText)
}
}
})
</script>這時候想獲取頁面最新的DOM節(jié)點,卻發(fā)現(xiàn)獲取到的仍然是舊值。

這是因為message數(shù)據(jù)在發(fā)現(xiàn)變化的時候,vue并不會立刻去更新Dom,而是將修改數(shù)據(jù)的操作放在了一個異步操作隊列中,如果我們一直修改相同數(shù)據(jù),異步操作隊列還會進行去重,等待同一事件循環(huán)中的所有數(shù)據(jù)變化完成之后,會將隊列中的事件拿來進行處理,進行DOM的更新。
為什么要有nexttick
{{num}}
for(let i=0; i<100000; i++){
num = i
}
如果沒有 nextTick 更新機制,那么 num 每次更新值都會觸發(fā)視圖更新(上面這段代碼也就是會更新10萬次視圖),有了nextTick機制,只需要更新一次,所以nextTick本質是一種優(yōu)化策略。
二、使用場景
this.testMsg="修改后的值";
console.log(this.$refs.aa.innerText); //that.$refs.aa獲取指定DOM,輸出:原始值
Vue.nextTick(function(){
console.log(document.querySelector('#firstBtn').innerText)
})

組件內使用vm.$nextTick() 實例方法只需要通過this. $nextTick(),并且回調函數(shù)中的 this 將自動綁定到當前的 Vue 實例上
this.message = '修改后的值'
console.log(this.$refs.aa.innerText) // => '原始的值'
this.$nextTick(function () {
console.log(this.$refs.aa.innerText) // => '修改后的值'
})
$nextTick() 會返回一個 Promise 對象,可以是用async/await完成相同作用的事情
await Vue.nextTick()
console.log(document.querySelector('#firstBtn').innerText)
三、實現(xiàn)原理
- callbacks也就是異步操作隊列
- callbacks新增回調函數(shù)后又執(zhí)行了timerFunc函數(shù),pending是用來標識同一個時間只能執(zhí)行一次。
export function nextTick(cb?: Function, ctx?: Object) {
let _resolve;
// cb 回調函數(shù)會經(jīng)統(tǒng)一處理壓入 callbacks 數(shù)組
callbacks.push(() => {
if (cb) {
// 給 cb 回調函數(shù)執(zhí)行加上了 try-catch 錯誤處理
try {
cb.call(ctx);
} catch (e) {
handleError(e, ctx, 'nextTick');
}
} else if (_resolve) {
_resolve(ctx);
}
});
// 執(zhí)行異步延遲函數(shù) timerFunc
if (!pending) {
pending = true;
timerFunc();
}
// 當 nextTick 沒有傳入函數(shù)參數(shù)的時候,返回一個 Promise 化的調用
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve;
});
}
}- timerFunc函數(shù)定義,這里是根據(jù)當前環(huán)境支持什么方法則確定調用哪個,分別有:Promise.then、MutationObserver、setImmediate、setTimeout;
- 通過上面任意一種方法,進行降級操作
export let isUsingMicroTask = false
if (typeof Promise !== 'undefined' && isNative(Promise)) {
//判斷1:是否原生支持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]'
)) {
//判斷2:是否原生支持MutationObserver
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)) {
//判斷3:是否原生支持setImmediate
timerFunc = () => {
setImmediate(flushCallbacks)
}
} else {
//判斷4:上面都不行,直接用setTimeout
timerFunc = () => {
setTimeout(flushCallbacks, 0)
}
}- 無論是微任務還是宏任務,都會放到flushCallbacks使用
- 這里將callbacks里面的函數(shù)復制一份,同時callbacks置空
- 依次執(zhí)行callbacks里面的函數(shù)
function flushCallbacks () {
pending = false
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}小結:
- 把回調函數(shù)放入callbacks等待執(zhí)行;
- 將執(zhí)行函數(shù)放到微任務或者宏任務中;
- 事件循環(huán)到了微任務或者宏任務,執(zhí)行函數(shù)依次執(zhí)行callbacks中的回調。
到此這篇關于Vue NextTick介紹與使用原理的文章就介紹到這了,更多相關Vue NextTick內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
使用Vue實現(xiàn)調用接口加載頁面初始數(shù)據(jù)
今天小編就為大家分享一篇使用Vue實現(xiàn)調用接口加載頁面初始數(shù)據(jù),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-10-10
vue parseHTML函數(shù)源碼解析 AST預備知識
這篇文章主要為大家介紹了vue parseHTML函數(shù)源碼解析 AST預備知識示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07
解決Vue axios post請求,后臺獲取不到數(shù)據(jù)的問題方法
今天小編就為大家分享一篇解決Vue axios post請求,后臺獲取不到數(shù)據(jù)的問題方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08
Vue 關閉當前頁、關閉當前標簽tagsView的實現(xiàn)方法
這篇文章主要介紹了Vue 關閉當前頁、關閉當前標簽tagsView,主要有兩種方式,一種是在vue頁面直接實現(xiàn),另一種在js文件中寫自定義函數(shù),在vue頁面中調用,本文通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-08-08
原生JS實現(xiàn)Vue transition fade過渡動畫效果示例
這篇文章主要為大家介紹了原生JS實現(xiàn)Vue transition fade過渡動畫效果示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06
Vue3中reactive變量重新賦值無法響應的3種處理方法
這篇文章主要給大家介紹了關于Vue3中reactive變量重新賦值無法響應的3種處理方法,在Vue3中可以使用reactive函數(shù)將一個普通對象轉換為響應式對象,需要的朋友可以參考下2023-08-08
深入淺析Vue中mixin和extend的區(qū)別和使用場景
Vue中有兩個較為高級的靜態(tài)方法mixin和extend,接下來給大家介紹Vue中mixin和extend的區(qū)別和使用場景,感興趣的朋友一起看看吧2019-08-08

