详解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 相关文章推荐
Firebug 字幕文件JSON地址获取代码
Oct 28 Javascript
jQuery EasyUI API 中文文档 - Form表单
Oct 06 Javascript
js querySelector和getElementById通过id获取元素的区别
Apr 20 Javascript
jquery购物车实时结算特效实现思路
Sep 23 Javascript
jQuery中选择器小问题(新人难免遇到)
Mar 31 Javascript
调整小数的格式保留小数点后两位
May 14 Javascript
JS特效实现图片自动播放并可控的效果
Jul 31 Javascript
JavaScript面向对象分层思维全面解析
Nov 22 Javascript
ReactNative之键盘Keyboard的弹出与消失示例
Jul 11 Javascript
jQuery实现使用sort方法对json数据排序的方法
Apr 17 jQuery
vue如何将v-for中的表格导出来
May 07 Javascript
vue项目使用$router.go(-1)返回时刷新原来的界面操作
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 和 HTML
2006/10/09 PHP
PHP开发不能违背的安全规则 过滤用户输入
2011/05/01 PHP
自定义session存储机制避免会话保持问题
2014/10/08 PHP
Laravel框架查询构造器 CURD操作示例
2019/09/04 PHP
Laravel ORM 数据model操作教程
2019/10/21 PHP
getElementById在任意一款浏览器中都可以用吗的疑问回复
2007/05/13 Javascript
js中for in的用法示例解析
2013/12/25 Javascript
js解决select下拉选不中问题
2014/10/14 Javascript
JS判断元素是否在数组内的实现代码
2016/03/30 Javascript
详解JavaScript中this关键字的用法
2016/05/26 Javascript
JavaScript浏览器对象模型BOM(BrowserObjectModel)实例详解
2016/11/29 Javascript
解决BootStrap Fileinput手机图片上传显示旋转问题
2017/06/01 Javascript
基于jstree使用AJAX请求获取数据形成树
2017/08/29 Javascript
Vue-cli3项目配置Vue.config.js实战记录
2018/07/29 Javascript
js验证密码强度解析
2020/03/18 Javascript
原生js实现密码强度验证功能
2020/03/18 Javascript
JS实现炫酷轮播图
2020/11/15 Javascript
[01:14]辉夜杯战队访谈宣传片—NEWBEE.Y
2015/12/26 DOTA
[00:43]魔廷新尊——痛苦女王至宝捆绑包
2020/06/12 DOTA
[01:08:29]DOTA2-DPC中国联赛定级赛 RNG vs Aster BO3第一场 1月9日
2021/03/11 DOTA
详解Django通用视图中的函数包装
2015/07/21 Python
python3中dict(字典)的使用方法示例
2017/03/22 Python
Python字典及字典基本操作方法详解
2018/01/30 Python
python图书管理系统
2020/04/05 Python
浅谈python3发送post请求参数为空的情况
2018/12/28 Python
python 通过麦克风录音 生成wav文件的方法
2019/01/09 Python
flask项目集成swagger的方法
2020/12/09 Python
澳大利亚网上书店:QBD
2021/01/09 全球购物
在校生钳工实习自我鉴定
2013/09/19 职场文书
爱岗敬业演讲稿范文
2014/01/14 职场文书
庆八一活动方案
2014/01/25 职场文书
年终总结会议主持词
2014/03/17 职场文书
货车司机岗位职责
2014/03/18 职场文书
教师爱岗敬业演讲稿
2014/05/05 职场文书
少先队活动总结
2014/08/29 职场文书
postgreSQL数据库基础知识介绍
2022/04/12 PostgreSQL