Vue NextTick介紹與使用原理
一、NextTick是什么
定義
在下次 DOM 更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)。在修改數(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本質(zhì)是一種優(yōu)化策略。
二、使用場景
this.testMsg="修改后的值"; console.log(this.$refs.aa.innerText); //that.$refs.aa獲取指定DOM,輸出:原始值 Vue.nextTick(function(){ console.log(document.querySelector('#firstBtn').innerText) })
組件內(nèi)使用vm.$nextTick() 實例方法只需要通過this. $nextTick(),并且回調(diào)函數(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新增回調(diào)函數(shù)后又執(zhí)行了timerFunc函數(shù),pending是用來標識同一個時間只能執(zhí)行一次。
export function nextTick(cb?: Function, ctx?: Object) { let _resolve; // cb 回調(diào)函數(shù)會經(jīng)統(tǒng)一處理壓入 callbacks 數(shù)組 callbacks.push(() => { if (cb) { // 給 cb 回調(diào)函數(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 化的調(diào)用 if (!cb && typeof Promise !== 'undefined') { return new Promise(resolve => { _resolve = resolve; }); } }
- timerFunc函數(shù)定義,這里是根據(jù)當前環(huán)境支持什么方法則確定調(diào)用哪個,分別有: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) } }
- 無論是微任務(wù)還是宏任務(wù),都會放到flushCallbacks使用
- 這里將callbacks里面的函數(shù)復(fù)制一份,同時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]() } }
小結(jié):
- 把回調(diào)函數(shù)放入callbacks等待執(zhí)行;
- 將執(zhí)行函數(shù)放到微任務(wù)或者宏任務(wù)中;
- 事件循環(huán)到了微任務(wù)或者宏任務(wù),執(zhí)行函數(shù)依次執(zhí)行callbacks中的回調(diào)。
到此這篇關(guān)于Vue NextTick介紹與使用原理的文章就介紹到這了,更多相關(guān)Vue NextTick內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue在自定義組件上使用v-model和.sync的方法實例
自定義組件的v-model和.sync修飾符其實本質(zhì)上都是vue的語法糖,用于實現(xiàn)父子組件的"數(shù)據(jù)"雙向綁定,下面這篇文章主要給大家介紹了關(guān)于vue在自定義組件上使用v-model和.sync的相關(guān)資料,需要的朋友可以參考下2022-07-07利用Vite2和Vue3實現(xiàn)網(wǎng)站國際化的全過程
vite2已經(jīng)出來一段時間了,最近沒忍住嘗試了一下,這篇文章主要給大家介紹了關(guān)于利用Vite2和Vue3實現(xiàn)網(wǎng)站國際化的相關(guān)資料,需要的朋友可以參考下2021-08-08vue3.0 proxy設(shè)置代理不成功的問題及解決方案
這篇文章主要介紹了vue3.0 proxy設(shè)置代理不成功的問題及解決方案,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-12-12