Abiel1024 / blog

Abiel's blog

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

vuex源码分析二(了解Store构造函数)

Abiel1024 opened this issue · comments

commented

构造函数Store

在我们使用vuex时,通常是这样:

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

实例化一个Store类,传入的也就是我们定义好的 actions、getters、mutations、state等,甚至当我们有多个子模块的时候,我们可以添加一个 modules 对象。所以最核心的部分就是Store类了。
因为内容比较多,所以一定要分开一部分一部分看。

先总的看store.js中定义的store类
image

虽然代码有很多,但是并不是一下子就用到,在我们new一个store实例的时候,传入一个对象,会先调用constructor方法。

constructor

通过代码分析:
第一部分

  if (!Vue && typeof window !== 'undefined' && window.Vue) {
    install(window.Vue)
  }

  if (process.env.NODE_ENV !== 'production') {
    assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`)
    assert(typeof Promise !== 'undefined', `vuex requires a Promise polyfill in this browser.`)
    assert(this instanceof Store, `store must be called with the new operator.`)
  }

  const {
    plugins = [],
    strict = false
  } = options

这一部分显示判断了是否已经执行了install方法,如果没有就重新install。
接下来是在非正式环境利用assert‘断言函数’,判断了Vue、Promise、至于第三个还不是特别明白,等以后明白了在补充吧。
assert‘断言函数’,在util.js中。对条件进行判断,判断为失败,则报错。

export function assert (condition, msg) {
  if (!condition) throw new Error(`[vuex] ${msg}`)
}

非常的简单,但是这种编程方式很优雅。

接下来利用es6 的结构赋值拿到 options 里的plugins 和 strict。plugins 表示应用的插件、strict 表示是否开启严格模式。结合下面的两行代码,分别把模式赋值到本身对象中,以及注入插件。

  // strict mode
  this.strict = strict

  // apply plugins
  plugins.forEach(plugin => plugin(this))

插件的功能的话就不多说了。严格模式下会观测所有的 state 的变化,建议在开发环境时开启严格模式,线上环境要关闭严格模式,否则会有一定的性能开销。

第二部分

  // store internal state
  this._committing = false
  this._actions = Object.create(null)
  this._actionSubscribers = []
  this._mutations = Object.create(null)
  this._wrappedGetters = Object.create(null)
  this._modules = new ModuleCollection(options)
  this._modulesNamespaceMap = Object.create(null)
  this._subscribers = []
  this._watcherVM = new Vue()

  // bind commit and dispatch to self
  const store = this
  const { dispatch, commit } = this
  this.dispatch = function boundDispatch (type, payload) {
    return dispatch.call(store, type, payload)
  }
  this.commit = function boundCommit (type, payload, options) {
    return commit.call(store, type, payload, options)
  }

这一部分主要是声明了store内部的一些属性,以及改变dispatch和commit的this指向。

  • ._committing 标志一个提交状态,作用是保证对 Vuex 中 state 的修改只能在 mutation 的回调函数中,而不能在外部随意修改 state。
  • this._actions 用来存储用户定义的所有的 actions。
  • this._actionSubscribers 用来存储所有派发 action 的订阅者,主要是提供给插件辅助开发。
  • this._mutations 用来存储用户定义所有的 mutatins。
  • this._wrappedGetters 用来存储用户定义的所有 getters 。
  • this._modules = new ModuleCollection(options) 将配置转成Module实例。下面在具体分析。
  • this._modulesNamespaceMap = Object.create(null) 用来存储用户开启namespaced的module,主要在map方法中用到。
  • this._subscribers = [] 用来存储所有对 mutation 变化的订阅者。主要是提供给插件辅助开发。
  • this._watcherVM = new Vue()是一个 Vue 对象的实例,主要是利用 Vue 实例方法 $watch 来观测变化的。

下面这段则是利用call将dispatch和commit方法的this指向知道当前store

  this.dispatch = function boundDispatch (type, payload) {
    return dispatch.call(store, type, payload)
  }
  this.commit = function boundCommit (type, payload, options) {
    return commit.call(store, type, payload, options)
  }

第三部分

  // strict mode
  this.strict = strict

  const state = this._modules.root.state

  // init root module.
  // this also recursively registers all sub-modules
  // and collects all module getters inside this._wrappedGetters
  installModule(this, state, [], this._modules.root)

  // initialize the store vm, which is responsible for the reactivity
  // (also registers _wrappedGetters as computed properties)
  resetStoreVM(this, state)

  // apply plugins
  plugins.forEach(plugin => plugin(this))

  if (Vue.config.devtools) {
    devtoolPlugin(this)
  }

关于严格模式和插件就不多说了,这里只是多了一个如果检测到devtools就自动注入devtooPlugin。
剩下的也是最重要的就是installModuleresetStoreVM