溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Vue.$nextTick的原理是什么

發(fā)布時間:2023-03-02 09:12:58 來源:億速云 閱讀:95 作者:iii 欄目:編程語言

這篇文章主要介紹了Vue.$nextTick的原理是什么的相關(guān)知識,內(nèi)容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Vue.$nextTick的原理是什么文章都會有所收獲,下面我們一起來看看吧。

Vue中DOM更新機制

當(dāng)你氣勢洶洶地使用Vue大展宏圖的時候,突然發(fā)現(xiàn),咦,我明明對這個數(shù)據(jù)進行更改了,但是當(dāng)我獲取它的時候怎么是上一次的值(本人比較懶,就不具體舉例了?)

此時,Vue就會說:“小樣,這你就不懂了吧,我的DOM是異步更新的呀!??!”

簡單的說,Vue的響應(yīng)式并不是只數(shù)據(jù)發(fā)生變化之后,DOM就立刻發(fā)生變化,而是按照一定的策略進行DOM的更新。這樣的好處是可以避免一些對DOM不必要的操作,提高渲染性能。

在Vue官方文檔中是這樣說明的:

可能你還沒有注意到,Vue異步執(zhí)行DOM更新。只要觀察到數(shù)據(jù)變化,Vue將開啟一個隊列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)改變。如果同一個watcher被多次觸發(fā),只會被推入到隊列中一次。這種在緩沖時去除重復(fù)數(shù)據(jù)對于避免不必要的計算和DOM操作上非常重要。然后,在下一個的事件循環(huán)“tick”中,Vue刷新隊列并執(zhí)行實際 (已去重的) 工作。

白話一點就是說,其實這是和JS當(dāng)中的事件循環(huán)是息息相關(guān)的,就是Vue不可能對每一個數(shù)據(jù)變化都做一次渲染,它會把這些變化先放在一個異步的隊列當(dāng)中,同時它還會對這個隊列里面的操作進行去重,比如你修改了這個數(shù)據(jù)三次,它只會保留最后一次。這些變化是都可以通過隊列的形式保存起來,那現(xiàn)在的問題就來到了,那vue是在事件循環(huán)的哪個時機來對DOM進行修改呢?

Vue有兩種選擇,一個是在本次事件循環(huán)的最后進行一次DOM更新,另一種是把DOM更新放在下一輪的事件循環(huán)當(dāng)中。z這時,尤雨溪拍了拍胸脯說:“這兩種方法,我都有!” 但是因為本輪事件循環(huán)最后執(zhí)行會比放在下一輪事件循環(huán)要快很多,所以Vue優(yōu)先選擇第一種,只有當(dāng)環(huán)境不支持的時候才觸發(fā)第二種機制。(??開頭的鏈接讓你懂事件循環(huán))

雖然性能上提高了很多,但這個時候問題就出現(xiàn)了,我們都知道在一輪事件循環(huán)中,同步執(zhí)行棧中代碼執(zhí)行完成之后,才會執(zhí)行異步隊列當(dāng)中的內(nèi)容,那我們獲取DOM的操作是一個同步的呀!!那豈不是雖然我已經(jīng)把數(shù)據(jù)改掉了,但是它的更新異步的,而我在獲取的時候,它還沒有來得及改,所以會出現(xiàn)文章開頭的那個問題。

這。。。我確實需要進行這樣操作,那這么辦呢??

沒關(guān)系啦,尤大很貼心的為我們提供了Vue.$nextTick()

Vue.$nextTick()

其實一句話就可以把$nextTick這個東西講明白:就是你放在$nextTick 當(dāng)中的操作不會立即執(zhí)行,而是等數(shù)據(jù)更新、DOM更新完成之后再執(zhí)行,這樣我們拿到的肯定就是最新的了。

再準(zhǔn)確一點來講就是$nextTick方法將回調(diào)延遲到下次DOM更新循環(huán)之后執(zhí)行。(看不懂這句人話的,可以看上面[狗頭])

意思我們都懂了,那$nextTick是怎樣完成這個神奇的功能的呢? 核心如下:

Vue在內(nèi)部對異步隊列嘗試使用原生的Promise.thenMutationObserversetImmediate,如果執(zhí)行環(huán)境不支持,則會采用 setTimeout(fn, 0)代替。

仔細地看這句話,你就可以發(fā)現(xiàn)這不就是利用 JavaScript 的這些異步回調(diào)任務(wù)隊列,來實現(xiàn) Vue 框架中自己的異步回調(diào)隊列。這其實就是一個典型的將底層 JavaScript 執(zhí)行原理應(yīng)用到具體案例中的示例。

我在這里稍微總結(jié)一下:就是$nextTick將回調(diào)函數(shù)放到微任務(wù)或者宏任務(wù)當(dāng)中以延遲它地執(zhí)行順序;(總結(jié)的也比較懶?)

重要的是理解源碼中它的三個參數(shù)的意思:

  • callback:我們要執(zhí)行的操作,可以放在這個函數(shù)當(dāng)中,我們沒執(zhí)行一次$nextTick就會把回調(diào)函數(shù)放到一個異步隊列當(dāng)中;

  • pending:標(biāo)識,用以判斷在某個事件循環(huán)中是否為第一次加入,第一次加入的時候才觸發(fā)異步執(zhí)行的隊列掛載

  • timerFunc:用來觸發(fā)執(zhí)行回調(diào)函數(shù),也就是Promise.thenMutationObserversetImmediatesetTimeout的過程

理解之后,在看整個$nextTick里面的執(zhí)行過程,其實就是把一個個$nextTick中的回調(diào)函數(shù)壓入到callback隊列當(dāng)中,然后根據(jù)事件的性質(zhì)等待執(zhí)行,輪到它執(zhí)行的時候,就執(zhí)行一下,然后去掉callback隊列中相應(yīng)的事件。

使用

說了這么多,怎么用它呢? 很簡單很簡單

mounted: function () {
  this.$nextTick(function () {
    // Code that will run only after the
    // entire view has been rendered
  })
}

使用場景

  • created中獲取DOM的操作需要使用它

  • 就是我們上面的例子,你如果想要獲取最新值,就用它

  • 還有一些第三方插件使用過程中,使用到的情況,具體問題具體分析

補充

之前我一直搞不懂一個的問題,$nextTick既然把它傳入的方法變成微任務(wù)了,那它和其它微任務(wù)的執(zhí)行順序是怎樣的呢?

這簡單來說就是誰先掛載Promise對象的問題,在調(diào)用$nextTick方法時就會將其閉包內(nèi)部維護的執(zhí)行隊列掛載到Promise對象,在數(shù)據(jù)更新時Vue內(nèi)部首先就會執(zhí)行$nextTick方法,之后便將執(zhí)行隊列掛載到了Promise對象上,其實在明白JsEvent Loop模型后,將數(shù)據(jù)更新也看做一個$nextTick方法的調(diào)用,并且明白$nextTick方法會一次性執(zhí)行所有推入的回調(diào),就可以明白執(zhí)行順序的問題了

還有$nextTicknextTick區(qū)別就是nextTick多了一個context參數(shù),用來指定上下文。但兩個的本質(zhì)是一樣的,$nextTick是實例方法,nextTick是類的靜態(tài)方法而已;實例方法的一個好處就是,自動給你綁定為調(diào)用實例的this罷了。

關(guān)于“Vue.$nextTick的原理是什么”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“Vue.$nextTick的原理是什么”知識都有一定的了解,大家如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

vue
AI