現代前端框架的變更檢查機制
目的
- 了解現代 framework 要解決的問題
- 從另一個角度比較各個現代 framework
- Not a tutorial
為何需要現代前端框架?
- 避免頁面 flash
- 前後端分離
- 只關注 Data 操作
- 去除重複瑣碎的 DOM 操作
為何需要現代前端框架
- 避免頁面 flash
- 前後端分離
- 只關注 Data 操作
- 去除重複瑣碎的 DOM 操作
- 把 Data 投影 到 UI(DOM) 上

只關注 Data 操作的好處
- view & business logic 間的關注點分離
- 減少瑣碎的 DOM 操作
- Data 即畫面
把資料對應到畫面上的難點
- 第一次 render 都很簡單,把 Data 都全部顯示到 UI 上就好
- server side rendering
- 所有畫面都從 server 來,並且都是一次性的
- 前端不需要管理狀態
- server side rendering
- 但如果涉及 Data (狀態) 的改變就沒那麼容易
- 要怎麼知道開發者改了甚麼 data?
- 不知道那些 data 改變的話,如何把變更投影到 UI 上?
把改變的 Data 投影到 UI 上的方法
-
不知道啥 data 改變,每個都檢查過就知道了
-
AngularJS
-
Angular
-
-
才不管啥 data 改變,全部重 render 就對了
-
React
-
-
我知道啥 data 改變了,因為被改變時會收到通知
-
Vue
-
把改變的 Data 投影到 UI 上的方法
-
不知道啥 data 改變,每個都檢查過就知道了
-
AngularJS
-
Angular
-
-
才不管啥 data 改變,全部重 render 就對了
-
React
-
-
我知道啥 data 改變了,因為被改變時會收到通知
-
Vue
-
不知道啥 data 改變,每個都檢查過就知道了
-
Dirty Checking
-
AngularJS
-
Angular
-

AngularJS - Dirty Checking
-
機制:
-
所有 watcher 都檢查 data 有沒有改變 (digest loop)
-
template/$watcher 都算是 watcher
-
-
每次會執行 2~10 次的 digest loop 來檢查值
-
因為 child 也可能改變 parent
-
Graph, not Tree
-
-
-


<h1>Hello {{yourName}}!</h1>AngularJS - Dirty Checking
-
什麼時候檢查?
-
每個非同步動作被觸發的時候就檢查
-
e.g. 點擊,XHR,timeout ...etc
-
API:
-
template: 提供 ng 開頭的 api 來觸發檢查
-
js: 提供 $ 開頭的 api 來觸發檢查
-
-
//js api example
$timeout(function() {
$scope.greetings = "Hello World!";
}, 5000);//html api example
<button ng-click="greeting()">Hello</button>Angular - Dirty Checking
-
機制:
-
所有 watcher 都檢查 data 有沒有改變 (digest loop)
-
只會由上往下檢查一次
- 規定 child 不能影響 parent,否則會忽略/報錯
- unidirectional flow
- Tree, not Graph
-


Angular - Dirty Checking
-
什麼時候檢查?
-
每個非同步動作被更新的時候就檢查
-
e.g. 點擊,XHR,timeout ...etc
-
API:
-
template: (event)
-
js: Angular 會 patch 所有的非同步 API
-
每個非同步 API 中都加上 hook 通知 Angular 更新
-
因此無須額外的 js API 可以觸發檢查
-
-
-
//html api example
<button (click)="greeting()">Hello</button>Angular vs. AngularJS
-
Unidirectional flow
-
減少 API
-
AOT (Ahead of Time) 技術
- 優化程式碼,compiler friendly code
-
減少動態語法
Angular vs. AngularJS
-
Unidirectional flow
-
減少 API
-
AOT 技術
在 Change Detection 的速度上快了 3~10x
把改變的 Data 投影到 UI 上的方法
-
不知道啥 data 改變,每個都檢查過就知道了
-
AngularJS
-
Angular
-
-
才不管啥 data 改變,全部重 render 就對了
-
React
-
-
我知道啥 data 改變了,因為被改變時會收到通知
-
Vue
-
才不管啥 data 改變,直接全部重 render
-
React
-
只要狀態改變,就整個 Component 重 render
-
效仿 Server Rendering
-
因此不需要關注 Data 改變的差異
-
Data 改變就全部重 render
-
-
Performance?
-
DOM 操作很慢
-
parse、repaint、reflow
-
- 重複 render 沒改變的畫面很浪費
-
-
才不管啥 data 改變,直接全部重 render
-
Performance?
- Virtual DOM
React - Virtual DOM
-
機制:
-
React render 時先呼叫 virtual DOM render
-
以 JS 物件模擬 DOM 結構
-
即 virtual DOM
-
-
與先前的 virtual DOM 做 diff
-
把 diff 的部分 patch 回真實的 DOM 中
-
React - Virtual DOM
-
用途:
-
為 render 到 DOM 前的緩衝層
-
可想成 DOM 層面的變更檢查機制
-
-
優點:
-
實際上只會讓 DOM 去 re-render 有 diff 的部分
-
解決全部重 render 會拖慢速度的問題
-
React - Virtual DOM
-
什麼時候 Render Virtual DOM?
-
ReactDOM.render
-
通常整個 APP 只會有一個
-
-
component.setState
-
// render api example
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
// setState api example
this.setState({greetings: 'Hello World'});把改變的 Data 投影到 UI 上的方法
-
不知道啥 data 改變,每個都檢查過就知道了
-
AngularJS
-
Angular
-
-
才不管啥 data 改變,全部重 render 就對了
-
React
-
-
我知道啥 data 改變了,因為被改變時會收到通知
-
Vue
-
我知道啥 data 改變了,因為被改變時會收到通知
- Vue
- 依賴收集
- 觀察者模式
- 依賴收集
Vue - 依賴收集
-
機制:
-
使用 Data 內部的提供 getter & setter
-
Object.defineProperty
-
-
Data 被 get 時,會把 get 他的 watcher 當成 subscriber
-
Data 被 set 時,會 notify 他的 subscribers
-
watcher 觸發 virtual DOM 的 render
-

<h1>Hello {{yourName}}!</h1>Vue - 依賴收集
-
要觀察哪些 data?
-
API:
-
new Vue
-
<h1>Hello {{yourName}}!</h1>
var vm = new Vue({
el: '#app2',
data: {
yourName: 'Henry'
},
});把改變的 Data 投影到 UI 上的方法
-
不知道啥 data 改變,每個都檢查過就知道了
-
AngularJS
-
Angular
-
-
才不管啥 data 改變,全部重 render 就對了
-
React
-
-
我知道啥 data 改變了,因為被改變時會收到通知
-
Vue
-
結論
- 如何 變更偵測 是各個 framework 致力於解決的最大問題
- 變更偵測的方式會影響到 framework API 的設計
- 每個 framework 都使用了一些很 hack 的手法來解決問題
References
Change Detections in modern Front End Frameworks
By Chang Henry
Change Detections in modern Front End Frameworks
- 104