通俗易懂Vuex原始碼導讀0-全域性介紹

毛靜文發表於2019-02-14

本系列文章目的

  • 真正的程式碼解析

    • 網上有很多關於「vuex原始碼解析」的文章。但可能筆者水平有限,總覺得這些文章不太直觀。

    • 部分文章只是在按順序逐個js檔案進行介紹,並沒有根據程式的執行邏輯介紹,也沒有與官方文件進行對應。

    • 只有當真正理解了原始碼以後才恍然大悟,哦!原來文章是這個意思。

    • 但這時文章已經失去了幫助理解原始碼,幫助解析的意義。

      Momo圖

  • 本文通過以下方式幫助閱讀,理解原始碼

    • 給出資料結構,並介紹各資料的意義。

    • 丟擲結論,即給出原始碼的整體執行原理。

    • 按照程式執行邏輯進行介紹,摒棄常規逐個檔案進行介紹的方法。按照邏輯順序進行介紹。

    • 對應官網的介紹文章進行介紹。

    • 儘量圖文豐富,穿插表情包,讓學習過程更愉悅些。

    • 通過以上的方式,帶著整體印象去看原始碼,逐步進行驗證,加深理解。不用一頭霧水地猜原始碼。

      Momo圖

  • 希望能通過系列文章

    • 能將vuex原始碼邏輯講清楚,幫助大家理解原始碼。

    • 讓大家瞭解vuex的實現機制,使用起來更踏實,打破顧慮。

    • 也希望藉此消除大家對原始碼的恐懼,養成閱讀原始碼的習慣。

      Momo圖

文章閱讀方式,及流程

  • 正如前面所說,需要事先了解下文給出的「變數介紹」,「執行原理」。起碼要有個印象,後續講解中,能帶著結論,不斷去印證。

  • 按順序閱讀,由於程式碼解析是根據程式執行邏輯進行介紹的,前後相互關聯,所以需要按照順序閱讀

  • 但當內容較為複雜,巢狀太深時,會拆分出來講。可以先點選連結,跳轉到細則中看完,再回到主邏輯繼續閱讀

  • 本文講得比較細,可能略顯繁瑣,大神請多包涵。理解能力強的同學,可以選擇性跳過。

    Momo圖

原始碼除錯方法

Momo圖

  • 雖然本文用不到,但可能有些同學想要自己打斷點,打日誌檢視實際執行過程,所以在此進行介紹

  • 辦法很簡單,修改 vuex 庫的索引源即可。例如修改示例中的 example->counter->store.js 檔案

    import Vue from 'vue'
    // import Vuex from 'vuex'
    import Vuex from '../../src/index'
    複製程式碼
  • 原理是,將原本對庫的檔案(build之後,被壓縮過的)索引,改成對vuex原始檔的索引

  • '../../src/index'/src/index.js檔案,即vuex原始碼的入口檔案

  • 修改後,參考 package.json 的說明,在目錄下執行命令列npm run dev,即可執行示例程式

  • 在原始碼後打的日誌或者斷點,就能在示例中執行

執行原理(重點)

Momo圖

  • 通過變數 _modules 變數儲存配置項模組樹(其資料結構與配置項的資料結構相同,相當於配置檔案的拷貝,只是對資料進行了些處理)

  • 通過 state 變數儲存與 _modules 模組樹相同結構的 state 結構樹,只是內容比較純粹,全是state變數。

    • 對應下圖,獲取c變數,則為state(頂層module的state,即moduleA).moduleB.moduleC.c,
    • 子模組被當做 state 的一部分,以模組名為 key ,模組的 state 為 value 進行關聯
    moduleA:{
      ...,
      state:{a:'a'},
      modules:{
        moduleB:{
            ...,
            state:{b:'b'},
            modules:{
              moduleC:{
                state:{c:'c'},
              }
            }
          }
      }
    }
    複製程式碼
  • 通過 _actions,_mutations,getters 陣列儲存所有模組配置中的 action, mutation,getter函式

    • 如模組A,和模組B均有一個action函式actionFun,記做actionFun1和actionFun2。
    • 則 _actions.actionFun = [actionFun1,actionFun2]
    • 如果模組設定了名稱空間,則在儲存函式時,往函式名中新增名稱空間層級字首。
    • 如模組C也有一個 action 函式actionFun,記做actionFun3,但由於設定了名稱空間字首,在_actions中儲存時,將這樣儲存_actions['C/action'] = actionFun3
  • 呼叫 commit,dispatch,getter 時,從上面定義的容器中,找到同名的陣列,順序呼叫裡面的函式

  • 資料繫結的效果,通過 Vue 的 watch,computed 特性完成

  • 總的來說,除了module和state使用了樹結構,其他的都通過陣列變數容器儲存,需要用到的時候,再從裡面拿。和我們簡單地通過全域性變數儲存沒太大的區別。只是做出了規範。

變數介紹(重點)

Momo圖

用得比較多的,出現比較頻繁的變數,預先介紹一下

  • 【_committing】提交狀態

    • 嚴格模式時,只要當_committing給false才可以修改state內容,用於防止非commit方式修改state(例如直接對state的變數進行賦值)。
  • 【_actions】action 函式陣列物件容器

    • 儲存所有action函式陣列,如 _actions.actionFun = [actionFun1,actionFun2]
    • 呼叫 dispatch 函式時,將獲取 _actions 的同名陣列,依次呼叫陣列裡面的函式
  • 【_mutations】 mutation 函式陣列物件容器

    • 資料結構與_actions相同
    • 呼叫 commit 函式時,將獲取 _mutations 的同名陣列,順序執行陣列中儲存的函式
  • 【_wrappedGetters】

    • 儲存 getter 函式的函式陣列物件容器。
    • 通過this.$store.getters 獲取的就是 _wrappedGetters 物件,只是中間進行了一些處理
  • 【_modules】模組樹,通過樹結構,儲存配置檔案內容

  • 【store】儲存物件

    • 即this.$store,即整個vuex功能的實現函式,可以理解為vuex的物件例項
    • 【store._vm】vuex內部儲存的vue物件例項,用於藉助 vue 的 watch 函式和 computed 函式實現資料響應
    • 【store.getters】即 this.$store.getter,最終將呼叫 _wrappedGetters
  • 【path】模組層級陣列

    • 儲存各個祖先模組的名字的陣列,例如
    moduleA:{ // 對應path為[]
      ...,
      modules:{
        moduleB:{ // 對應path為['A']
            ...,
            modules:{
              moduleC:{}  // 對應path為['A','B']
            }
          }
      }
    }
    複製程式碼

原始碼檔案介紹

Momo圖

  • 【module】 模組相關處理的資料夾
    • 【module.js】 生成模組物件
    • 【module-collection.js】 遞迴解析模組配置,生成由「module.js 」的模組物件組成的模組樹
  • 【plugins】 外掛相關,與主體功能無關
    • 【devtool.js】 chrome 的 vue 除錯外掛中使用到的程式碼,主要實現資料回滾功能
    • 【logger.js】 日誌列印相關
  • 【helpers.js】 輔助函式,mapGetters,mapActions,mapMutations等函式的實現
  • 【index.esm.js】入口檔案
  • 【index.js】入口檔案
  • 【mixin.js】vue 混合函式,實現 vuex 的安裝功能
  • 【store.js】vuex 儲存類,實現 vuex 的主體功能。
  • 【util.js】工具函式庫,複用一些常用函式

文章原稿,帶註釋原始碼,戳這裡

文章持續輸出中,原始碼註釋還未完全整理,純當閱讀筆記,大神請勿較真

Momo圖

下一篇文章將正式講解原始碼,從Vuex的安裝過程開始講起

總目錄

Momo圖

不給錢,點個贊也行啊~

相關文章