Angular(06)- 為什么數(shù)據(jù)變化,綁定的視圖就會自動更新了?

這里提一點,前端三大框架(Angular,React,Vue)的數(shù)據(jù)驅(qū)動來更新視圖的原理,即 MVVM 的實現(xiàn)。
為什么數(shù)據(jù)發(fā)生變化,綁定的視圖就會刷新了呢?

以下是我的個人理解,僅供參考:

在還是 jQuery 的時代,當在 js 中改變了某個變量的數(shù)據(jù),而這個變量是需要在 Html 中顯示出來的。那么,這個時候,我們的做法也就是通過 DOM 先獲取到顯示該變量的視圖元素,然后借助 DOM API 來更新這個視圖元素,是吧。這是原始的方式。

那么,不管三大框架都做了些什么,MVVM 的實現(xiàn)原理是什么,它們最終其實也都還是要通過操縱 DOM API 來更新視圖元素,與原始方式的區(qū)別就是,這部分操縱 DOM 的工作,由框架來負責,我們無需關心了,只需要關心數(shù)據(jù)的變化工作即可。

好處就是,我們可以更關注于業(yè)務邏輯的編程,而無須再去為如何操縱 DOM 樹而煩惱。

那么,既然框架要來幫我們處理這部分工作,它們實現(xiàn)的關鍵點就在于,如何知道,我們對數(shù)據(jù)進行了更新?

什么意思?也就是說,這部分工作由我們自己來做時,我們是能夠明確的知道什么時候該去操縱 DOM 樹了,不就是我們對數(shù)據(jù)進行更新的時刻嗎。但,框架并不知道我們什么時刻會對數(shù)據(jù)進行更新。

所以,回想一下,你在使用三大框架時,是不是每個框架基本都有一些注意事項,或者說它的規(guī)定?

比如說:

react 要求修改 state 局部變量時,得通過 this.setState(...)
vue 要求得聲明在 data 中的變量,當它變化時才會被追蹤到,以更新視圖

為什么這些框架會有這些要求,或者說這些規(guī)定?
因為它需要知道我們到底什么時刻會去對數(shù)據(jù)進行更新啊。

對于 react 來說,當我們需要更新變量的數(shù)據(jù)值時,都通過調(diào)用它的方法,那么,它自然就知道我們什么時候更新了數(shù)據(jù)了。

對于 vue 來說,雖然我們更新數(shù)據(jù)時是直接對變量進行賦值操作,但實際上,聲明在 data 中的這些變量,都會被轉(zhuǎn)換成存取器屬性,也就是 set 和 get。那么,當我們直接對變量的賦值操作,其實會去執(zhí)行 set 的內(nèi)部邏輯,而 vue 只需要在這里就可以獲取我們更新數(shù)據(jù)的時機了。

那么,對于 Angular 呢?好像使用 Angular 過程中,并沒有需要遵循什么規(guī)定。

這是因為,Angular 的實現(xiàn)原理并不類似于 react 和 vue。

react 和 vue 的原理類似于主動通知的模式,也就是,當我發(fā)生變化了,那我就通知你一下,你就需要去做些更新處理了。

Angular 的原理,類似于被動輪詢的模式。也就是,你不知道我什么時候會變化,那么你就在我有可能會變化的情況下,不斷的讀取我的值,比對一下,看看有沒有發(fā)生變化。

驗證 Angular 的這種原理的猜測很簡單,你在頁面上某個元素綁定個方法,方法內(nèi)打個日志,然后你滑動下頁面試試看,看看日志是不是一直在輸出。

總結(jié)一下:
三大框架實現(xiàn)的原理其實有所差異
react 是通過調(diào)用 setState() 方式來告知視圖刷新;
vue 是通過將聲明在 data 中的數(shù)據(jù)屬性轉(zhuǎn)換為存取器數(shù)據(jù)(set 和 get)的方式,來監(jiān)聽數(shù)據(jù)變化的時機;
angular 則是在會觸發(fā)視圖變化的情況下,主動去檢測綁定的數(shù)據(jù)源,比對下是否有發(fā)生變化來判斷是否需要刷新視圖。

當然,以上的理解僅僅是很淺的層面,只是理清了三大框架是如何知道我們數(shù)據(jù)更新的時機這個問題。

對于三大框架來說,他們的視圖刷新并非是這么簡單的實現(xiàn)。比如說:

對于 vue,當它監(jiān)聽到某個數(shù)據(jù)源發(fā)生變化了,但它并不會立馬去刷新視圖,而是將相關的信息先記錄起來,等待一個固定頻率的下個幀信號,在這期間發(fā)生變化的數(shù)據(jù)源都會被記錄起來。直到信號來的時候,再一起去處理這次的視圖刷新。

這也是為什么一些 vue 的書中或者項目中,會有要求說某些代碼需要放在下一個 tick 中去執(zhí)行,因為數(shù)據(jù)源剛發(fā)生變化時,頁面不一定就更新了。

原理跟 Android 的屏幕刷新機制很像,就都是以一個固定頻率來刷新頁面,在每個幀信號之間,只是收集發(fā)生變化的視圖,或者說,只更新虛擬 DOM,并不會去更新真實的頁面。直到幀信號到的時候,再一次性的批處理地刷新頁面。

對于 Angular 來說,雖然它是不斷輪詢的方式來檢測數(shù)據(jù)源是否發(fā)生變化,但并不意味著時時刻刻都在輪詢檢測,而只在一些有可能導致視圖更新的場景下才會去檢測。比如說,滑動頁面,比如說 settimeout 事件。

這也是為什么在 Angular 項目中,經(jīng)常會看到一些 settimeout(..., 0) 這樣的操作。

以上,個人的理解,如有錯誤,歡迎指點一下。

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

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

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