通俗易懂Vuex源碼導讀2-Store的建立及模塊樹介紹

Store對象的建立

上一章,咱們介紹了Vuex組件的安裝過程,安裝的最後,進行了對Store對象的引用(或對Store的建立)。本章將介紹Store(Vuex存貯類)的建立。html

建立語句索引

  • 建立Vuex的語句爲new Vuex.Store({...})
  • Vuex的入口文件爲index.js,Store是index.js導出的Store類。
  • Store類是store.js中定義的,因此打開store.js文件,並找到Store的構造函數constructor。

Store的構造函數constructor

  • 【判斷vuex是否已經被注入】兼容Vue組件的另外一種注入方法,即將vue掛載在window對象上。自動檢測window.Vue,若是有掛載,並且沒有被註冊過。則調用註冊方法。

    圖

  • 【一些斷言】斷言是否被註冊,斷言是否支持promise,斷言類有沒有被正確的實例化。這些斷言語句,在vue build出來之後。報錯信息會被忽略掉。前端

    圖

    • 在webpack配置中,npm build時,會將 process.env.NODE_ENV 設置爲true
    • 例如,咱們找到使用Vue-cli 產生的 webpack配置的 Vue 項目,找到 /build/webpack.prod.conf.js 文件

      圖

    • 咱們能夠看到 const env = require('../config/prod.env'),即 env = { NODE_ENV: '"production"' }
    • 而後再經過 webpack.DefinePlugin({ 'process.env': env }), 將 env 變量注入到前端環境的變量中去
    • 從而將node中的變量(後端變量),注入到前端環境中。webpack.DefinePlugin的詳細介紹參考這裏
  • 各項數據容器的定義,部分重要容器,咱們在第0章中詳細介紹過,(不理解的同窗,可回頭細讀)vue

    圖

    • this._committing = false // 提交狀態標識,在嚴格模式時,防止非commit操做下,state被修改
    • this._actions = Object.create(null) // action 函數的數組的對象,保存全部action回調函數,node

      • // 從null中建立對象,Object.create(null)沒有繼承任何原型方法,也就是說它的原型鏈沒有上一層。從而定義純粹的對象
    • this._mutations = Object.create(null) // mutation 函數的數組的對象,保存全部的mutations回調函數,
    • this._subscribers = [] // 訂閱 mutation 操做的函數數組。裏面的每一個函數,將在 commit 執行完成後被調用,該功能經常使用於插件,與主功能無關
    • this._actionSubscribers = [] // 訂閱 action 操做的函數數組。裏面的每一個函數,將在 action函數被調用前被調用,該功能經常使用於插件,與主功能無關
    • this._wrappedGetters = Object.create(null) // 保存 getter 函數的函數數組對象容器。
    • this._modules = new ModuleCollection(options) // 解析並生成模塊樹,經過樹結構,保存配置文件內容
    • this._modulesNamespaceMap = Object.create(null) // 保存命名空間的模塊對象,以便在輔助函數createNamespacedHelpers中快速定位到帶命名空間的模塊
    • this._watcherVM = new Vue() // 定義一個Vue對象,Vue類在調用Vuex安裝函數,install時,被傳遞進來
  • ModuleCollection方法內部較爲複雜,咱們在這裏介紹(爲了更好地理解程序邏輯,請按順序觀看,看完具體內容再往下看呦~)
  • 獲取 dispatch函數 與 commit函數,並複寫該函數webpack

    圖

    • 複寫的做用,是將兩個函數的 this 綁定到 Vuex 實例自己。防止 this 的指向被修改。
    • 由於這兩個函數,能夠經過 mapMutations 和 mapActions 輔助函數轉化爲 Vue 中的普通函數,這時 this 將指向 Vue 組件,而不是 Vuex 實例。因此在這裏先將this鎖定好。map輔助函數具體邏輯將在後續介紹,Map的使用例子
    • 兩個函數暫時還沒使用到,暫不進行介紹
  • 獲取根模塊的 state 變量索引, const state = this._modules.root.state
  • installModule,安裝根模塊(設置 commit , dispatch 函數的重載 : 根據是否設置命名空間,設置參數前綴。將 getter,commit,action 放到對應容器中保存起來。詳情看這裏
  • resetStoreVM,藉助 Vue 的 watch 功能和 computed 功能,實現數據的響應式。詳情看這裏
  • Vuex 插件註冊,有插件,則調用插件的函數,與主功能無關
  • 最後是Vue調試工具的相關處理,與主功能無關

    圖

  • 至此爲止,Store對象的建立過程,也是Vuex的建立過程,已經所有介紹完了,對總體數據結構有了大概瞭解。

    圖

  • 緊接着將對照 Vuex 官方使用文檔,針對 Vuex 在使用作的邏輯進行一一介紹

帶註釋源碼,戳這裏

源碼註釋還未徹底整理,純當閱讀筆記,大神請勿較真git

Momo圖

我又不要臉地來騙讚了

Momo圖

建立模塊樹 new ModuleCollection(options)

構造函數

圖

  • 形參rawRootModule,在Store中new ModuleCollection(options)傳入,而options是Store的構造函數參數,即咱們在生成Store實例,調用new Vuex.Store({...})時傳入的參數,如github

    {
      state,
      getters,
      actions,
      mutations,
    }
  • 形參名爲rawRootModule,顧名思義,是將配置文件做爲「原始根模塊」
  • 構造函數調用的是register函數,即構造函數的做用是註冊根模塊

註冊函數,register

  • 參數解析,path, rawModule, runtime = trueweb

    • path是被註冊模塊的層級關係數組,保存當前模塊及各個祖先模塊名字,如[a,b,c,當前模塊],則對應配置爲{modules:a{modules:{b:modules:{c:modules:{當前模塊}}}}}}
    • rawModule是模塊的配置參數,即在定義模塊時,開發者定義的模塊配置內容,如模塊的state,getters,actions等等
    • runtime表示是不是運行狀態,在運行狀態下,不能進行某些特定操做
  • 【assertRawModule】vuex

    圖

    • 對模塊的配置信息進行斷言
    • 判斷了getters,mutations,actions等配置項的數據類型是否正確。不正確則拋出異常
  • 建立模塊對象 const newModule = new Module(rawModule, runtime),找到module.js文件找到其構造函數。npm

    圖

    • 構造函數參數

      • rawModule 是模塊的配置信息對象,即在定義模塊時,開發者定義的模塊配置內容,如模塊的state,getters,actions等等
      • runtime表示是不是運行狀態,在運行狀態下,不能進行某些特定操做
    • 具體操做,

      • const rawState = rawModule.state 從配置參數中,獲取了state數據
      • this._children = Object.create(null) 定義了子模塊對象容器。Object.create(null)是爲定義一個純粹的對象
      • this._rawModule = rawModule 保存配置參數自己
      • this.state = (typeof rawState === 'function' ? rawState() : rawState) || {} 解析state,能夠是函數,運用工廠模式產生配置對象
  • 經過 path 數組判斷當前模塊是否爲根模塊

    圖

    • 若是是根模塊,則經過變量 this.root 保存
    • 不是根模塊,則經過 get方法 獲取父模塊對象

      • get方法傳入的是路徑數組,slice(0, -1) 是爲了去除本模塊名,保留全部祖先模塊的路徑,從而獲取父模塊
      • get函數內部,使用了數組的reduce方法

        圖

        • reduce函數有兩個參數,第一個是回調函數,第二個是初始值
        • 回調參數,參數一是該函數上一次的執行結果(即return值)或者reduce函數的第二參數設置的初始值。參數二,是被順序調用的數組中的元素
        • 該函數循環地對數組中的每一個元素進行函數處理,並將運行結果當作參數給下一次執行作參數
        • reduce函數的第二個參數,初始值是this.root,是前面保存起來的,根模塊配置
        • reduce內部執行的操做是module.getChild(key)
        • getChild調用的是模塊對象(Module)中的 getChill 函數,返回模塊的 _children 子模塊容器的特定子模塊

          圖

        • 整合而言,get的做用,是從根模塊出發,根據給出的path數組,循環尋找子模塊對象,
        • 因爲調用時,去除了本層次,因此獲取得的是本模塊的父模塊
      • 調用父模塊的addChild方法,path[path.length - 1]得到的是本模塊的名,newModule 是由本模塊配置文件生成的模塊對象

        • addChild 與 getChild 相對應,是往模塊對象的 _children 子模塊容器裏面,以子模塊名(path的元素)爲key值,添加子模塊
        • 對應了上一步,獲取parent的方法
  • if (rawModule.modules),判斷模塊配置信息中,有沒有子模塊的配置

    圖

    • 若是有,則遞歸調用註冊函數register自己
    • 傳入的參數一,加上了子模塊名的 patn 模塊層級數組,rawChildModule是子模塊配置文件,runtime是繼承而來的運行時標識,暫時還沒用上
  • 小結

    • 根據上面的步驟,完成了模塊的遞歸註冊,經過模塊的_children容器保存子模塊的連接(以子模塊名爲key,對應模塊對象爲value),造成了模塊樹結構
    • 每一個模塊對象,包含state,和_rawModule,原配置信息
    • 看完這裏記得回到「Store的構造函數」觀看後續操做哦

總目錄

相關文章
相關標籤/搜索