首頁 > web前端 > Vue.js > 帶你深入了解Vue.$nextTick(原理淺析)

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

青灯夜游
發布: 2023-03-01 20:03:37
轉載
2156 人瀏覽過

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

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

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

Vue中DOM更新機制

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

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

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

#在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罷了。

(學習影片分享:vuejs入門教學程式設計基礎影片

以上是帶你深入了解Vue.$nextTick(原理淺析)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:juejin.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板