详解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 相关文章推荐
javascript模仿msgbox提示效果代码
Jun 10 Javascript
JQUERY的属性选择符和自定义选择符使用方法(二)
Apr 07 Javascript
jQuery实现简单网页遮罩层/弹出层效果兼容IE6、IE7
Jun 16 Javascript
jQuery制作简洁的图片轮播效果
Apr 03 Javascript
JavaScript入门系列之知识点总结
Mar 24 Javascript
JQuery 传送中文乱码问题的简单解决办法
May 24 Javascript
jQuery多文件异步上传带进度条实例代码
Aug 16 Javascript
jquery自定义表单验证插件
Oct 12 Javascript
详解Js中的模块化是如何实现的
Oct 18 Javascript
微信小程序实现动态改变view标签宽度和高度的方法【附demo源码下载】
Dec 05 Javascript
详解Vue底部导航栏组件
May 02 Javascript
Vue中的this.$options.data()和this.$data用法说明
Jul 26 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/09/05 PHP
杏林同学录(五)
2006/10/09 PHP
PHP 表单提交给自己
2008/07/24 PHP
PHP安全技术之 实现php基本安全
2010/09/04 PHP
PHP防盗链的基本思想 防盗链的设置方法
2015/09/25 PHP
修改PHP脚本使WordPress拦截垃圾评论的方法示例
2015/12/10 PHP
PHP中串行化用法示例
2016/11/16 PHP
Thinkphp5行为使用方法汇总
2017/12/21 PHP
PHP中__set()实例用法和基础讲解
2019/07/23 PHP
Jquery中删除元素的实现代码
2011/12/29 Javascript
JavaScript面向对象(极简主义法minimalist approach)
2012/07/17 Javascript
原生JS实现表单checkbook获取已选择的值
2013/07/21 Javascript
javascript模拟post提交隐藏地址栏的参数
2014/09/03 Javascript
angular.element方法汇总
2015/01/07 Javascript
js控制div层的叠加简单方法
2016/10/15 Javascript
JS实现页面中所有img对象添加onclick事件及新窗口查看图片的方法
2016/12/27 Javascript
JSON 数据格式详解
2017/09/13 Javascript
axios发送post请求,提交图片类型表单数据方法
2018/03/16 Javascript
Javasript设计模式之链式调用详解
2018/04/26 Javascript
Vue 实现输入框新增搜索历史记录功能
2019/10/15 Javascript
Vue+Openlayers自定义轨迹动画
2020/09/24 Javascript
python strip() 函数和 split() 函数的详解及实例
2017/02/03 Python
python使用opencv按一定间隔截取视频帧
2018/03/06 Python
numpy中实现二维数组按照某列、某行排序的方法
2018/04/04 Python
python/sympy求解矩阵方程的方法
2018/11/08 Python
Python3字符串encode与decode的讲解
2019/04/02 Python
基于nexus3配置Python仓库过程详解
2020/06/15 Python
Python用SSH连接到网络设备
2021/02/18 Python
多视角3D逼真HTML5水波动画
2016/03/03 HTML / CSS
Opodo英国旅游网站:预订廉价航班、酒店和汽车租赁
2018/07/14 全球购物
美术专业自荐信
2014/07/07 职场文书
庆祝国庆节标语
2014/10/09 职场文书
大学生社会实践感想
2015/08/11 职场文书
python 用递归实现通用爬虫解析器
2021/04/16 Python
python实战之一步一步教你绘制小猪佩奇
2021/04/22 Python
《勇者辞职不干了》上卷BD发售宣传CM公开
2022/04/08 日漫