Vuex原始碼學習(四)module與moduleCollection

酸楚與甘甜發表於2019-03-26

如果你還不知道Vuex是怎麼安裝的,請移步Vuex原始碼學習(三)install都做了哪些事情

整合模組

這一節該分析模組的是怎麼被整合的,以及要整合成什麼樣子。

Vuex原始碼學習(四)module與moduleCollection
在Vuex的constructor中比較靠前的位置有這麼兩行程式碼,_modules屬性是ModuleCollection的例項物件,之後 _modules屬性被頻繁使用,

這塊就是對Vuex的模組進行了一次整合,整合出一個可以被使用的 _modules,而_moduleNamespaceMap是一個空物件

該怎麼整合模組?

先看一下我們我們專案中Store的結構 store/index.js

Vuex原始碼學習(四)module與moduleCollection
moduleList:

Vuex原始碼學習(四)module與moduleCollection

moduleSet:

Vuex原始碼學習(四)module與moduleCollection

結構就是這樣的

Vuex原始碼學習(四)module與moduleCollection
在以上程式碼中的modules下的資料,我都稱它是偽(未加工)模組,因為它還不具有模組的功能。 當我們例項化Vuex.Store這個類的時候接收的引數options就會直接交給moduleCollection來處理。引數options是什麼呢?就是上面圖中這樣結構的資料, 想要處理成什麼樣子? 下面看一下ModuleCollection是怎麼處理的

export default class ModuleCollection {
  constructor (rawRootModule) {
    // register root module (Vuex.Store options)
    // 註冊模組並連結
    this.register([], rawRootModule, false)
  }
  ...
  register (path, rawModule, runtime = true) {
    if (process.env.NODE_ENV !== 'production') {
     // 不符合規則的模組會報錯。
      assertRawModule(path, rawModule)
    }
    // 建立一個模組
    const newModule = new Module(rawModule, runtime)
    if (path.length === 0) {
      this.root = newModule
    } else {
      // path.slice(0,-1)就可以拿到父模組的path。
      // get方法可以根據path來找到對應的模組。
      const parent = this.get(path.slice(0, -1))
      // 將子模組掛載到父模組上
      parent.addChild(path[path.length - 1], newModule)
    }
    // register nested modules
    if (rawModule.modules) {
      // 遍歷每個模組的modules(目的是獲取所有子模組)
      forEachValue(rawModule.modules, (rawChildModule, key) => {
      // 為什麼要path.concat(key)?
        // 依次註冊子模組。
        this.register(path.concat(key), rawChildModule, runtime)
      })
    }
  }
}
複製程式碼

在Vuex與vue-router的原始碼中,命名變數是很有規律的, 在開發人員使用這兩個框架的時候,傳遞進去的引數,在使用時命名的變數名都是raw開頭的,代表是未經過加工的。

Vuex原始碼學習(四)module與moduleCollection

將未經過加工的偽模組處理成真正可以使用的模組。

在初始化的時候直接開始註冊模組, moduleCollection的這個類的任務是把生成的模組合理的連結起來,而模組的生成交給了Module這個類。

所以register方法就是把根模組以及所有的子模組從一個偽(未加工)模組變成一個真正的模組並且連結起來。 遍歷樹形結構用什麼方法? 遞迴!

register都做了什麼?

  1. 篩選出不符合規則的模組,報錯提示。
  2. 將偽(未加工)模組加工成一個真正的模組。
  3. 將加工好的模組掛載在它的父模組上。
  4. 如果這個模組有modules屬性(模組有自己的子模組)讓每個子模組重複以上操作

遞迴的出口:rawModule.modules為false(模組沒有子模組) ,也就是每個模組都沒有子模組需要註冊了,那就代表全部加工與連結完畢。

分析register的三個引數

register接收三個引數,path、rawModule、hot。

hot這個引數目前看來不關鍵。

rawModule是偽(未加工)模組

那path的作用是什麼呢?

path的作用很大,大家類比下前端頁面的dom樹的Xpath,如果我想知道這個節點的位置,需要知道這個父節點的位置,然後一層一層的向上知道根結點,有了Xpath就可以直接找到這個節點,

Vuex也是一樣的想知道某個模組的位置,只需要提供根結點到他的一個path,path按順序儲存著根模組到它本身的所有祖先模組(根模組沒有名字,又不能把第一個放一個空,所以path裡 面沒有根模組),在每次註冊的時候,這個模組有子模組,就把它的path加上(concat)子模組的名字,在子模組執行register方法時,path就比它的父模組多一個父模組的名字,所以根模組註冊的時候傳入path就是[](空陣列)了。

ModuleCollection的get方法可以根據path來獲取指定的模組,在掛載的時候十分有用,

Vuex原始碼學習(四)module與moduleCollection
,使用reduce的方法,按照陣列的順序,一層一層的找目標模組。

path對以後要講的設定名稱空間也很有幫助。

總結

  1. ModuleCollection這個類,主要完成了模組的連結與整合,生成模組的任務交給了Module這個類。
  2. 模組的連結與整合通過遞迴完成。
  3. path可以讓moduleCollection快速找到對應模組。

下一章講述生成的module具體可以做什麼

我是一個應屆生,最近和朋友們維護了一個公眾號,內容是我們在從應屆生過渡到開發這一路所踩過的坑,已經我們一步步學習的記錄,如果感興趣的朋友可以關注一下,一同加油~

個人公眾號:鹹魚正翻身

相關文章