mobx源碼解讀(四):講講autorun和reaction

NO IMAGE

原文地址:mobx autorun

文本是 mobx 源碼解讀系列 第四篇

本系列文章全部採用 mobx 較新版本:v5.13.0

mobx 源碼解讀 issue,歡迎討論

技術前提

在閱讀之前,希望你對以下技術有所瞭解或實踐,不然可能會影響你對本文的理解

  1. ES6 裝飾器:decorator

  2. ES6 代理:proxy

  3. ES6 反射:reflect

  4. 定義對象屬性:Object.defineProperty

  5. 實現簡易版 觀察者模式

  6. 實現簡易版 MVVM(可選)

準備

  1. 這篇文章和 mobx 源碼解讀系列(三) 有很強的關聯,建議先看懂再看文本

  2. 上篇講的 mobx 中的依賴收集 可以濃縮為一個函數:schedule,這篇我們討論該函數是如何使用的

  3. 說明:mobx 對於依賴收集的優化是非常多的,其中包括 computedValuePOSSIBLY_STALE 狀態和 shouldComputed 判斷等等,喜歡的自行 dive in 吧

上源碼

一、Reaction

  1. Reaction 最重要的兩個函數:onInvalidate 和 track

前者作用是對變化作出反應,為構造函數參數,後者作用是收集依賴

試想,將兩者結合到一起:根據變化自動收集依賴,然後作出反應。這不就是 autorun 嗎

那 schedule 函數又是啥呢,其實它最終調的就是 track + onInvalidate

mobx源碼解讀(四):講講autorun和reaction

  1. schedule 的處理

首先將 reaction push 到 globalState.pendingReactions 中,作為 runReactions 中 while 的調用對象(詳見:上篇

while 循環中調用每個 reaction 的 runReaction 方法

在裡面加了各種鎖,最後調用 onInvalidate 方法,那 track 方法在哪調呢

mobx源碼解讀(四):講講autorun和reaction

  1. autorun

答案是 new Reaction 時通過構造函數,將自己的 track 方法塞到 onInvalidate 中

track 函數的入參為 view 函數,那麼通過執行 view 就知道依賴了哪些 observables,那麼就可以記錄到當前 reaction 中

這樣就將 track、view 方法結合為 onInvalidate,形成了順序:

數據變化 -> observables 遍歷 observers 並調用其 schedule(裡面調用 track 再調 view) -> view 通過 get 代理獲取數據並重新 bind derivation 和 observable 的依賴 -> 計算完畢,view 執行完成,視圖更新

問題:傳參這麼繞,為啥不直接在將 view 當做 Reaction 的入參傳進去,在裡面調用 track 呢,代碼如下:

這樣做是有原因且合理的,文末 “下章劇透” 告訴你

mobx源碼解讀(四):講講autorun和reaction

new Reaction(name, view); // 直接傳 view
class Reaction {
constructor(public name: string, private view: (r: Reaction) => void) {}
runReaction() {
// ...
this.track(this.view);
}
track(fn) {
const result = trackDerivedFunction(this, fn, undefined)
}
}
  1. track 方法如何收集依賴的呢

當然是上篇講的 trackDerivedFunction。同理,computedValue 對它依賴的數據也是如此

在 get 代理中重新收集依賴,發現 value 改變後就向觀察自己的觀察者發出信號

mobx源碼解讀(四):講講autorun和reaction

mobx源碼解讀(四):講講autorun和reaction

二、其他“對 observables 作出響應”

em…,autorun 就講完了,其實 autorun 中最重要也是 mobx 核心之一的是 trackDerivedFunction 方法

  1. reaction(小寫)

reaction 允許我們主動申明依賴,並在依賴改變是自動執行副作用

換湯不換藥,將 track 自動收集換成了手動傳入即可

在 new Reaction 時傳參,將 expression 傳入 track,判斷是否改變再執行 effect

mobx源碼解讀(四):講講autorun和reaction

  1. when

when 可以根據傳的第一個參數,為 true 時執行 effect。如果沒傳 effect 則返回一個 promise,供 async await 使用

when 直接由 predicate 決定是否執行 effect,不依賴 observable,用 predicate 代替 track 即可

mobx源碼解讀(四):講講autorun和reaction

三、action

我們設置 configure({ enforceActions: 'always' }) 就必需在 action 下才能改變數據

  1. action 函數和裝飾器

這個就不多說了,namedActionDecorator 最後調的也是 createAction

mobx源碼解讀(四):講講autorun和reaction

  1. createAction 調用 executeAction 開啟了“切分支”之旅

在 _startAction 保存各種之前分支的信息,然後進入 action 執行:fn.apply,執行完後將 runInfo 傳給 _endAction 恢復之前信息

其中 untrackedStart:將 globalState.trackingDerivation 置為 null,防止錯誤收集依賴(詳見:上篇),即在 action 期間不進行依賴收集(get 代理)

startBatch:鎖住 inBatch,即在 action 期間也不進行實際的 runReactions,而只是 push 到 globalState.pendingReactions,待 action 執行完後再 schedule

allowStateChangesStart:enforceActions 也是判斷該值是否為 ‘always’ 來決定是否可以在 action 改變 observable

這裡將 globalState.allowStateChanges 置為 true,即在 action 中一定可以改變 observable

讓 action 在“安靜”的情況下運行,主要還是為了優化,讓 action 全部改變完數據後,再進行依賴收集

mobx源碼解讀(四):講講autorun和reaction

mobx源碼解讀(四):講講autorun和reaction

  1. runInAction

runInAction(f) 是 action(f)() 的語法糖,那就是直接執行 executeAction 咯

mobx源碼解讀(四):講講autorun和reaction

最後

  1. 帶註釋的 mobx 源碼

  2. 歡迎在 mobx 源碼解讀 issue 中討論~

  3. 推薦:minbx: mini mobx,供學習使用,歡迎 pr:minbx 項目地址

  4. 下章劇透:如虎添翼的 mobx-react

  5. 碼字不易,喜歡的記得點 ❤️ 哦

相關文章

詳解設計模式建造者模式

高德APP全鏈路源碼依賴分析工程

javaWeb學習總結——文件上傳、下載

阿里巴巴業務平臺-招聘“前端、客戶端”開發,虛位以待