详解vuex之store源码简单解析


Posted in Javascript onJune 13, 2019

关于vuex的基础部分学习于https://3water.com/article/163008.htm

使用Vuex的时候,通常会实例化Store类,然后传入一个对象,包括我们定义好的actions、getters、mutations、state等。store的构造函数:

export class Store {
 constructor (options = {}) {
  // 若window内不存在vue,则重新定义Vue
  if (!Vue && typeof window !== 'undefined' && window.Vue) {
   install(window.Vue)
  }

  if (process.env.NODE_ENV !== 'production') {
   // 断言函数,来判断是否满足一些条件
   // 确保 Vue 的存在
   assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`)
   // 确保 Promsie 可以使用
   assert(typeof Promise !== 'undefined', `vuex requires a Promise polyfill in this browser.`)
   assert(this instanceof Store, `store must be called with the new operator.`)
  }

  // 解构赋值,拿到options里的plugins和strict
  const {
   plugins = [],
   strict = false
  } = options

  // 创建内部属性
  // 标志一个提交状态,作用是保证对 Vuex 中 state 的修改只能在 mutation 的回调函数中,而不能在外部随意修改 state
  this._committing = false 
  // 用来存储用户定义的所有的actions
  this._actions = Object.create(null)
  this._actionSubscribers = []
  // 用来存储用户定义所有的mutatins
  this._mutations = Object.create(null)
  // 用来存储用户定义的所有getters 
  this._wrappedGetters = Object.create(null)
  // 用来存储所有的运行时的 modules
  this._modules = new ModuleCollection(options)
  this._modulesNamespaceMap = Object.create(null)
  // 用来存储所有对 mutation 变化的订阅者
  this._subscribers = []
  // 一个 Vue对象的实例,主要是利用 Vue 实例方法 $watch 来观测变化的
  this._watcherVM = new Vue()

  // 把Store类的dispatch和commit的方法的this指针指向当前store的实例上
  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)
  }

  // 是否开启严格模式
  this.strict = strict

  const state = this._modules.root.state

  // Vuex的初始化的核心,其中,installModule方法是把我们通过options传入的各种属性模块注册和安装;
  // resetStoreVM 方法是初始化 store._vm,观测 state 和 getters 的变化;最后是应用传入的插件。
  installModule(this, state, [], this._modules.root)

  resetStoreVM(this, state)
  plugins.forEach(plugin => plugin(this))

  const useDevtools = options.devtools !== undefined ? options.devtools : Vue.config.devtools
  if (useDevtools) {
   devtoolPlugin(this)
  }
 }

Vuex本身是单一状态树,应用的所有状态都包含在一个大对象内,随着我们应用规模的不断增长,这个Store变得非常臃肿。为了解决这个问题,Vuex允许我们把store分模块。每一个模块包含各自的state、mutations、actions和getters,甚至还可以嵌套模块。

接下来看installModule方法:

function installModule (store, rootState, path, module, hot) {
 // 通过path数组的长度判断是否为根
 const isRoot = !path.length
 const namespace = store._modules.getNamespace(path)

 // register in namespace map
 if (module.namespaced) {
  store._modulesNamespaceMap[namespace] = module
 }

 // 第一次调用时,path为空,不进入if
 // 递归调用installModule安装子模块时,将执行该代码块
 if (!isRoot && !hot) {
  const parentState = getNestedState(rootState, path.slice(0, -1))
  // 模块名
  const moduleName = path[path.length - 1]
  // 把当前模块的state添加到parentState中。具体解析见下
  store._withCommit(() => {
   Vue.set(parentState, moduleName, module.state)
  })
 }

 const local = module.context = makeLocalContext(store, namespace, path)

 // 对mutations、actions、getters进行注册
 module.forEachMutation((mutation, key) => {
  const namespacedType = namespace + key
  registerMutation(store, namespacedType, mutation, local)
 })

 module.forEachAction((action, key) => {
  const type = action.root ? key : namespace + key
  const handler = action.handler || action
  registerAction(store, type, handler, local)
 })

 module.forEachGetter((getter, key) => {
  const namespacedType = namespace + key
  registerGetter(store, namespacedType, getter, local)
 })

 // 遍历modules,递归调用installModule安装子模块
 module.forEachChild((child, key) => {
  installModule(store, rootState, path.concat(key), child, hot)
 })
}
store的_withCommit方法定义是这样的:

 _withCommit (fn) {
  const committing = this._committing
  this._committing = true
  fn()
  this._committing = committing
 }

Vuex中所有对state的修改都会用_withCommit函数包装,保证在同步修改state的过程中this._committing的值始终为true。这样当我们观测 state的变化时,如果this._committing的值不为true,则能检查到这个状态修改是有问题的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
一段实现页面上的图片延时加载的js代码
Feb 11 Javascript
jquery多行滚动/向左或向上滚动/响应鼠标实现思路及代码
Jan 23 Javascript
ReactNative页面跳转实例代码
Sep 27 Javascript
最实用的jQuery分页插件
Oct 09 Javascript
RequireJs的使用详解
Feb 19 Javascript
使用get方式提交表单在地址栏里面不显示提交信息
Feb 21 Javascript
详解VUE的状态控制与延时加载刷新
Mar 27 Javascript
微信小程序实现顶部选项卡(swiper)
Jun 19 Javascript
vue2.0 根据状态值进行样式的改变展示方法
Mar 13 Javascript
关于React动态加载路由处理的相关问题
Jan 07 Javascript
基于JQuery实现页面定时弹出广告
May 08 jQuery
通过实例解析JavaScript常用排序算法
Sep 02 Javascript
vue store之状态管理模式的详细介绍
Jun 13 #Javascript
微信小程序页面间跳转传参方式总结
Jun 13 #Javascript
微信小程序位置授权处理方法
Jun 13 #Javascript
json数据格式常见操作示例
Jun 13 #Javascript
微信小程序实现渐入渐出动画效果
Jun 13 #Javascript
微信小程序前端自定义分享的实现方法
Jun 13 #Javascript
javascript数组常见操作方法实例总结【连接、添加、删除、去重、排序等】
Jun 13 #Javascript
You might like
生成静态页面的PHP类
2006/11/25 PHP
Yii使用技巧大汇总
2015/12/29 PHP
浅谈PHP面向对象之访问者模式+组合模式
2017/05/22 PHP
PHP编程快速实现数组去重的方法详解
2017/07/22 PHP
PHP Class SoapClient not found解决方法
2018/01/20 PHP
PHP的HTTP客户端Guzzle简单使用方法分析
2019/10/30 PHP
一个简单的JavaScript 日期计算算法
2009/09/11 Javascript
使用indexOf等在JavaScript的数组中进行元素查找和替换
2013/09/18 Javascript
常用的JavaScript验证正则表达式汇总
2013/11/26 Javascript
Jquery 实现图片轮换
2015/01/28 Javascript
javascript实现uploadify上传格式以及个数限制
2015/11/23 Javascript
javascript中的作用域和闭包详解
2016/01/13 Javascript
js操作浏览器的参数方法
2017/01/21 Javascript
js 转义字符及URI编码详解
2017/02/28 Javascript
Angular组件化管理实现方法分析
2017/03/17 Javascript
微信小程序之数据缓存的实例详解
2017/09/29 Javascript
js数组方法reduce经典用法代码分享
2018/01/07 Javascript
p5.js入门教程之鼠标交互的示例
2018/03/16 Javascript
解决vue-cli项目webpack打包后iconfont文件路径的问题
2018/09/01 Javascript
基于vue-cli npm run build之后vendor.js文件过大的解决方法
2018/09/27 Javascript
11个教程中不常被提及的JavaScript小技巧(推荐)
2019/04/17 Javascript
[02:38]DOTA2超级联赛专访Loda 认为IG世界最强
2013/05/27 DOTA
Python入门篇之字典
2014/10/17 Python
Python编程之多态用法实例详解
2015/05/19 Python
Python实现字符串反转的常用方法分析【4种方法】
2017/09/30 Python
Python变量赋值的秘密分享
2018/04/03 Python
wtfPython—Python中一组有趣微妙的代码【收藏】
2018/08/31 Python
如何用Python制作微信好友个性签名词云图
2019/06/28 Python
Python基于pyecharts实现关联图绘制
2020/03/27 Python
为什么说python更适合树莓派编程
2020/07/20 Python
英国男女奢华内衣和泳装购物网站:Figleaves
2017/01/28 全球购物
给校长的建议书400字
2014/05/15 职场文书
机关搬迁方案
2014/05/18 职场文书
小学学校门卫岗位职责
2014/08/03 职场文书
老龄工作先进事迹
2014/08/15 职场文书
小学毕业感言200字
2015/07/30 职场文书