帶你深入瞭解Vue.$nextTick(原理淺析)

2023-03-01 22:00:22

本篇文章給大家分享一下Vue純乾貨,介紹一下你不知道的Vue.nextTick,聊聊Vue.$nextTick的原理,希望對大家有所幫助!

原理性的東西就會文字較多,請耐下心來,細細品味

Vue中DOM更新機制

當你氣勢洶洶地使用Vue大展宏圖的時候,突然發現,咦,我明明對這個資料進行更改了,但是當我獲取它的時候怎麼是上一次的值(本人比較懶,就不具體舉例了?)

此時,Vue就會說:「小樣,這你就不懂了吧,我的DOM是非同步更新的呀!!!」

簡單的說,Vue的響應式並不是只資料發生變化之後,DOM就立刻發生變化,而是按照一定的策略進行DOM的更新。這樣的好處是可以避免一些對DOM不必要的操作,提高渲染效能。【相關推薦:、】

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

可能你還沒有注意到,Vue非同步執行DOM更新。只要觀察到資料變化,Vue將開啟一個佇列,並緩衝在同一事件迴圈中發生的所有資料改變。如果同一個watcher被多次觸發,只會被推入到佇列中一次。這種在緩衝時去除重複資料對於避免不必要的計算和DOM操作上非常重要。然後,在下一個的事件迴圈「tick」中,Vue重新整理佇列並執行實際 (已去重的) 工作。

白話一點就是說,其實這是和JS當中的事件迴圈是息息相關的,就是Vue不可能對每一個資料變化都做一次渲染,它會把這些變化先放在一個非同步的佇列當中,同時它還會對這個佇列裡面的操作進行去重,比如你修改了這個資料三次,它只會保留最後一次。這些變化是都可以通過佇列的形式儲存起來,那現在的問題就來到了,那vue是在事件迴圈的哪個時機來對DOM進行修改呢?

Vue有兩種選擇,一個是在本次事件迴圈的最後進行一次DOM更新,另一種是把DOM更新放在下一輪的事件迴圈當中。z這時,尤雨溪拍了拍胸脯說:「這兩種方法,我都有!」 但是因為本輪事件迴圈最後執行會比放在下一輪事件迴圈要快很多,所以Vue優先選擇第一種,只有當環境不支援的時候才觸發第二種機制。(??開頭的連結讓你懂事件迴圈)

雖然效能上提高了很多,但這個時候問題就出現了,我們都知道在一輪事件迴圈中,同步執行棧中程式碼執行完成之後,才會執行非同步佇列當中的內容,那我們獲取DOM的操作是一個同步的呀!!那豈不是雖然我已經把資料改掉了,但是它的更新非同步的,而我在獲取的時候,它還沒有來得及改,所以會出現文章開頭的那個問題。

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

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

Vue.$nextTick()

其實一句話就可以把$nextTick這個東西講明白:就是你放在$nextTick 當中的操作不會立即執行,而是等資料更新、DOM更新完成之後再執行,這樣我們拿到的肯定就是最新的了。

再準確一點來講就是$nextTick方法將回撥延遲到下次DOM更新迴圈之後執行。(看不懂這句人話的,可以看上面[狗頭])

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

Vue在內部對非同步佇列嘗試使用原生的Promise.thenMutationObserversetImmediate,如果執行環境不支援,則會採用 setTimeout(fn, 0)代替。

仔細地看這句話,你就可以發現這不就是利用 JavaScript 的這些非同步回撥任務佇列,來實現 Vue 框架中自己的非同步回撥佇列。這其實就是一個典型的將底層 JavaScript 執行原理應用到具體案例中的範例。

我在這裡稍微總結一下:就是$nextTick將回撥函數放到微任務或者宏任務當中以延遲它地執行順序;(總結的也比較懶?)

重要的是理解原始碼中它的三個引數的意思:

  • callback:我們要執行的操作,可以放在這個函數當中,我們沒執行一次$nextTick就會把回撥函數放到一個非同步佇列當中;
  • pending:標識,用以判斷在某個事件迴圈中是否為第一次加入,第一次加入的時候才觸發非同步執行的佇列掛載
  • timerFunc:用來觸發執行回撥函數,也就是Promise.thenMutationObserversetImmediatesetTimeout的過程

理解之後,在看整個$nextTick裡面的執行過程,其實就是把一個個$nextTick中的回撥函數壓入到callback佇列當中,然後根據事件的性質等待執行,輪到它執行的時候,就執行一下,然後去掉callback佇列中相應的事件。

使用

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

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

使用場景

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

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

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

參考

補充

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

這簡單來說就是誰先掛載Promise物件的問題,在呼叫$nextTick方法時就會將其閉包內部維護的執行佇列掛載到Promise物件,在資料更新時Vue內部首先就會執行$nextTick方法,之後便將執行佇列掛載到了Promise物件上,其實在明白JsEvent Loop模型後,將資料更新也看做一個$nextTick方法的呼叫,並且明白$nextTick方法會一次性執行所有推入的回撥,就可以明白執行順序的問題了

還有$nextTicknextTick區別就是nextTick多了一個context引數,用來指定上下文。但兩個的本質是一樣的,$nextTick是實體方法,nextTick是類的靜態方法而已;實體方法的一個好處就是,自動給你係結為呼叫範例的this罷了。

(學習視訊分享:、)

以上就是帶你深入瞭解Vue.$nextTick(原理淺析)的詳細內容,更多請關注TW511.COM其它相關文章!