Vuex原始碼學習(七)action和mutation如何被呼叫的(呼叫篇)

酸楚與甘甜發表於2019-04-01

前置篇不會那可不行!Vuex原始碼學習(六)action和mutation如何被呼叫的(前置準備篇) 在前置準備篇我們已經知道被處理好的action與mutation都被集中放置在哪裡了。下面就要看dispacth和commit如何去呼叫它們。

dispatch與commit的實現

commit:

Vuex原始碼學習(七)action和mutation如何被呼叫的(呼叫篇)
首先呢我們要校正引數,把傳入的引數整理下 主要是處理這種形式

// 接收一個物件
this.$store.commit({type : 'setName',name : 'xLemon'});
this.$store.commit('setName',{name : 'xLemon'});
這兩個基本等價。
只是第一種方式mutation接收的payload會比第二種多一個type屬性,
整理的部分並不關鍵
複製程式碼

type是我們要找的mutation的名字,如何找到mutation呢?

通過 this._mutations[type] 找到要執行的mutation
複製程式碼

所以type一定要是mutation的全名

所以我們通過commit找mutation的時候有名稱空間的時候就要輸入全名,(那種帶很多/的)。沒有這個名字的mutation容錯處理,然後在withCommit函式的包裹下,完成了mutation的執行(所有mutation啊,全名相同的mutation都會被執行)。然後呢遍歷_subscribers裡面的函式進行執行。

_subscribers這是什麼?在一開始我們可以註冊一些內容(函式),在commit完成時被通知執行。(觀察者模式)如何註冊在這一章就不多講了!後面章節會統一講述。

這就是commit做的事情。

dispatch呢?

Vuex原始碼學習(七)action和mutation如何被呼叫的(呼叫篇)
與commit大同小異, 也有一個_actionSubscribers的屬性,在dispatch執行之前全部呼叫。 對於dispatch Vuex推薦的是放置非同步任務,在註冊action的時候已經被強制promise化了,所以有多個同名action會通過Promise.all來處理。在action的前後都有對應的鉤子函式執行。

固定disptach與commit的this指向

//在vue元件內一個方法如果多次使用dispatch和commit,就會很麻煩。
this.$store.dispatch('xxx',payload);
this.$store.commit('xxx',payload);
const {dispatch,commit} = this.$store;
//這相當於建立變數,然後把this.$store的dispatch與commit賦值給它們。
//有經驗的都應該知道,函式dispatch和commit的this指向在嚴格模式下指向undefined。
// 非嚴格模式下指向window,
// 剛才的原始碼中我們也看到了,dispatch和commit都依賴於Store例項。怎麼辦??
複製程式碼

解決方法如下:

Vuex原始碼學習(七)action和mutation如何被呼叫的(呼叫篇)
dispatch和commit是Store原型鏈上的方法,在constructor內註冊了建構函式內的方法,把原型上的dispatch和commit進行了一個this指向的強制繫結,通過call讓兩個方法永遠指向Store的例項上,保證了dispatch和commit不會因為賦值給其餘變數等操作導致this指向改變從而發生問題

action與mutation函式的引數都有哪些?怎麼來的?

看一個簡單的mutation:

export const setName = function(state,payload)  {
  state.name = payload;
};
複製程式碼

這個時候不經意間有了一個疑惑?state哪裡來的。 這就要從mutation被註冊的函式內找原因了

Vuex原始碼學習(七)action和mutation如何被呼叫的(呼叫篇)
handle是我們要被註冊的一個mutation,entry是這個同名mutation的容器(儲存所有的這個名字的mutation,一般只有一個)在吧handle放入entry的過程中,

我們發現,entry是被一個函式包裹起來,然後將local.storepayload繫結到這個handle的引數上,然後把handle的this指向鎖定到了Store例項上,所以mutation在被commit呼叫的時候只傳入了一個引數payload, 但是mutation函式執行的時候就有了兩個引數。

下面看一下action:

Vuex原始碼學習(七)action和mutation如何被呼叫的(呼叫篇)
按照剛才的分析action在被dispatch呼叫的時候會接收一個引數,但是action執行的時候會接收兩個引數,第一個引數是個物件裡面有六項,真的是包羅永珍啊。。。我們看一下這個物件的六項

{
    dispatch : local.dispatch,
    commit:local.commit,
    getter: local.getters,
    state: local.state,
    rootGetters:store.getters,
    rootState:store.state
}
複製程式碼

分為兩種一種是local的、一種是store的。mutation中好像也有使用local,那麼local的意義是什麼呢?我們下一節會講述local的含義以及makeLocalContextmakeLocalGetters兩個函式的作用。 還是要給個小線索,在模組樹的層級很高的時候,我們在使用state的時候要一層一層找尋嗎?

總結

  1. dispatch與commit在執行的時候,都是根據傳入的全名action、mutation去Store例項的_actions、_mutations中找到對應的方法,進行執行的。
  2. dispatch和commit中都使用了this(指向Store例項),為了防止this的指向改變從而出現問題,就把原型上的dispatch與commit在constructor中處理到了例項本身,這個過程做了this指向的繫結(call)。
  3. action和mutation在執行的時候,引數都是在註冊的時候就繫結了一部分,所以action與mutation在使用的時候可以訪問到state等很多內容。

下一章;離開action與mutation 來討論一下local的含義以及makeLocalContextmakeLocalGetters兩個函式的作用

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

個人公眾號:鹹魚正翻身

相關文章