vue模板的首次渲染,和重新渲染,有哪些區(qū)別?

搞明白這個,能幫助我們理解開發(fā)中出現(xiàn)的很多問題。


一、我們先來回顧一下vue模板的渲染過程:

(1)執(zhí)行render函數(shù),生成虛擬DOM。

render函數(shù)是根據(jù)render、templete、el這三個選項得來的,優(yōu)先級依次降低。如果有render函數(shù),則直接使用;否則如果有templete選項,則把templete作為模板編譯成render函數(shù);否則把el的outerHTML作為模板編譯成render函數(shù)。單頁面組件中,使用<templete>標簽作為模板編譯成render函數(shù)。

render函數(shù)首次執(zhí)行時,會觸發(fā)模板依賴數(shù)據(jù)的getter,getter會記錄哪個模板用到了自己,同時模板也會記錄自己用到了哪些屬性,這個過程叫依賴收集。

每次模板重新渲染時,模板中的表達式、methods函數(shù)、全局函數(shù)都會重新執(zhí)行。因為render函數(shù)就是個函數(shù),當它執(zhí)行時,里面的表達式和函數(shù)都會跟著執(zhí)行。但這里面有一個例外,就是計算屬性,因為計算屬性會緩存結果,多用計算屬性是個好習慣。

(2)虛擬DOM和數(shù)據(jù)結合,生成真實的DOM。

(3)如果不是首次渲染,生成的虛擬DOM會和原來的進行比較,通過diff算法,計算出來最少的需要更新的DOM。

(4)如果是首次渲染,把DOM掛載到頁面中。如果是重新渲染,則更新DOM。這一步是vue能影響的最后一步。

(5)瀏覽器渲染頁面。這一步是瀏覽器渲染進程操作的,和vue無關。但vue可以在上一步里,計算出DOM的最小更新,來盡量避免回流和重繪。


二、首次渲染和重新渲染的不同

(1)執(zhí)行時機和原理不同

vue從創(chuàng)建實例,到mounted執(zhí)行結束,這一整個生命周期是一個同步的過程。意味著,如果你試圖在created前加async,來讓異步數(shù)據(jù)獲取完成后再進入beforeMount鉤子,是沒用的。

模板的首次渲染,也是一個同步的過程。它是從beforeMount的同步代碼結束開始,同步的生成虛擬DOM、真實DOM、掛載到頁面這一系列操作之后,最后進入mounted鉤子。

但是,從模板首次渲染完成,也就是從進入mounted鉤子開始,之后的渲染邏輯就完全不一樣了,被稱為異步更新隊列。如果說首次渲染是生命周期驅動的,那么重新渲染,就是數(shù)據(jù)的變化驅動的。

當模板所依賴的屬性被重新賦值時,該屬性的setter被觸發(fā)。因為這個屬性記錄了哪些模板用到了自己,它就通知這些模板的Watcher進入微任務隊列。在同一個事件循環(huán)中,如果一個模板所依賴的多個屬性發(fā)生改變,它不會被重復放入到微任務隊列。這就是我們所熟悉的,多次修改數(shù)據(jù),vue只會更新DOM一次。

哪些操作會導致模板的重新渲染呢?從mounted鉤子開始,所有對模板依賴數(shù)據(jù)的更改,都會導致模板的重新渲染。

比如,在mounted中同步修改數(shù)據(jù),在瀏覽器事件中修改數(shù)據(jù),在created中異步獲取數(shù)據(jù)后修改數(shù)據(jù)等。

(2)依賴數(shù)據(jù)不同

要注意的是,我們通常習慣在created里異步獲取數(shù)據(jù),異步數(shù)據(jù)是不會參與到模板的首次渲染中的。當異步數(shù)據(jù)獲取成功后,數(shù)據(jù)的改變會觸發(fā)模板的重新渲染。

模板首次渲染采用的數(shù)據(jù),是prop、data、計算屬性的初始值。更準確的說,是render函數(shù)開始執(zhí)行之前的數(shù)據(jù)。

那么,在beforeCreate、created、beforeMount里對數(shù)據(jù)進行的同步操作,是會作用于模板的首次渲染的。而所有的異步數(shù)據(jù),以及mounted中對數(shù)據(jù)的修改,首次渲染都是用不到的。

無論是首次渲染還是重新渲染,都是基于當前的數(shù)據(jù)。首次渲染時使用的是實例創(chuàng)建時的數(shù)據(jù)狀態(tài),而重新渲染則是基于數(shù)據(jù)變化后的最新狀態(tài)。


三、所以,知道這些有什么用?

(1)在給data中的屬性設初始值時,要考慮健壯性。不要忘了,這些初始值會用于模板的首次渲染。

在開發(fā)中我們經(jīng)常犯這樣的錯誤,就是沒有考慮data初始值對首次渲染的兼容。當然,有個好處是代碼會報錯,幫助我們發(fā)現(xiàn)錯誤。

給我們的啟發(fā)是什么呢?對data賦初值,能多賦,不要少賦。我以前喜歡把所有屬性初始值都設為null,這個習慣很不好,容易報錯。我們應該設置有意義的初始值,至少應該用[]、''、0這些代替null。

(2)開發(fā)中經(jīng)常出現(xiàn),進入頁面后某個元素閃一下沒了。

是因為我們在這個元素使用了v-if,首次使用初始值渲染時是有的,后面異步獲取數(shù)據(jù)后重新計算就沒了,所以會閃一下。

為了避免這個問題,我們應該養(yǎng)成一個習慣,就是元素默認是不顯示的,拿到異步數(shù)據(jù)后再決定是否顯示,這樣就避免了閃一下的情況出現(xiàn)。如果在元素上再加一個進入動畫,就更好了。

還有一個v-cloak指令也是解決閃爍問題的,好像是解決{{}}閃爍問題的,我還沒有用過。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容