详解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 获取滚动条位置等信息的函数
Sep 08 Javascript
在JavaScript中typeof的用途介绍
Apr 11 Javascript
浅析return false的正确使用
Nov 04 Javascript
遍历DOM对象内的元素属性示例代码
Feb 08 Javascript
基于jQuery实现定位导航位置效果
Nov 15 jQuery
vue引入ueditor及node后台配置详解
Jan 03 Javascript
vue2.0 computed 计算list循环后累加值的实例
Mar 07 Javascript
小程序云开发初探(小结)
Oct 24 Javascript
微信小程序带动画弹窗组件使用方法详解
Nov 27 Javascript
angularjs实现table表格td单元格单击变输入框/可编辑状态示例
Feb 21 Javascript
返回上一个url并刷新界面的js代码
Sep 12 Javascript
深入讲解Vue中父子组件通信与事件触发
Mar 22 Vue.js
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
一个odbc连mssql分页的类
2006/10/09 PHP
php木马webshell扫描器代码
2012/01/25 PHP
配置Nginx+PHP的正确思路与过程
2016/05/10 PHP
php实现基于pdo的事务处理方法示例
2017/07/21 PHP
Laravel 之url参数,获取路由参数的例子
2019/10/21 PHP
javascript多种数据类型表格排序代码分析
2010/09/11 Javascript
JavaScript高级程序设计 读书笔记之九 本地对象Array
2012/02/27 Javascript
node.js中的fs.lchown方法使用说明
2014/12/16 Javascript
js判断文本框剩余可输入字数的方法
2015/02/04 Javascript
悬浮广告方法日常收集整理
2016/03/18 Javascript
JAVA Web实时消息后台服务器推送技术---GoEasy
2016/11/04 Javascript
原生JS实现跑马灯效果
2017/02/20 Javascript
分享十三个最佳JavaScript数据网格库
2017/04/07 Javascript
JS实现遍历不规则多维数组的方法
2018/03/21 Javascript
angular6.0使用教程之父组件通过url传递id给子组件的方法
2018/06/30 Javascript
原来JS还可以这样拆箱转换详解
2019/02/01 Javascript
在vue中使用vuex,修改state的值示例
2019/11/08 Javascript
[01:28:43]2014 DOTA2华西杯精英邀请赛5 24 DK VS CIS
2014/05/25 DOTA
Python笔记(叁)继续学习
2012/10/24 Python
Python3中简单的文件操作及两个简单小实例分享
2017/06/18 Python
python切片及sys.argv[]用法详解
2018/05/25 Python
Python使用Pickle模块进行数据保存和读取的讲解
2019/04/09 Python
Python中IP地址处理IPy模块的方法
2019/08/16 Python
python通过实例讲解反射机制
2019/10/17 Python
python实现翻译word表格小程序
2020/02/27 Python
python中子类与父类的关系基础知识点
2021/02/02 Python
英国图书音像网站:Hive.co.uk(图书、电子书、DVD、蓝光、音乐CD等)
2017/10/16 全球购物
全球独特生活方式产品和礼品购物网站:AHAlife
2018/09/18 全球购物
师德学习感言
2014/01/31 职场文书
三下乡活动方案
2014/01/31 职场文书
酒店总经理助理职责
2014/02/12 职场文书
岗位廉政承诺书
2014/03/27 职场文书
感恩老师的演讲稿
2014/05/06 职场文书
2014年学习部工作总结
2014/11/12 职场文书
初中成绩单评语
2014/12/29 职场文书
导游词之扬州大明寺
2019/10/09 职场文书