详解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 相关文章推荐
dwr spring的集成实现代码
Mar 22 Javascript
JavaScript中的对象的extensible属性介绍
Dec 30 Javascript
JQuery实现级联下拉框效果实例讲解
Sep 17 Javascript
浅谈JavaScript前端开发的MVC结构与MVVM结构
Jun 03 Javascript
HTML5 canvas 9绘制图片实例详解
Sep 06 Javascript
使用jQuery和ajax代替iframe的方法(详解)
Apr 12 jQuery
vue form check 表单验证的实现代码
Dec 09 Javascript
JavaScript:ES2019 的新特性(译)
Aug 08 Javascript
微信小程序页面滚动到指定位置代码实例
Sep 07 Javascript
vue移动端使用canvas签名的实现
Jan 15 Javascript
vue中父子组件传值,解决钩子函数mounted只运行一次的操作
Jul 27 Javascript
Vue实现圆环进度条的示例
Feb 06 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
点评山进PR-D3L三波段收音机
2021/03/02 无线电
PHP执行zip与rar解压缩方法实现代码
2010/12/05 PHP
js实现DIV的一些简单控制
2007/06/04 Javascript
js判断ie版本号的简单实现代码
2014/03/05 Javascript
用IE重起计算机或者关机的示例代码
2014/03/10 Javascript
jQuery 获取兄弟元素的几种不错方法
2014/05/23 Javascript
jquery实现select下拉框美化特效代码分享
2015/08/18 Javascript
DOM事件阶段以及事件捕获与事件冒泡先后执行顺序(图文详解)
2015/08/18 Javascript
JavaScript知识点总结(十一)之js中的Object类详解
2016/05/31 Javascript
EasyUI折叠表格层次显示detailview详解及实例
2016/12/28 Javascript
AngularJs表单校验功能实例代码
2017/02/09 Javascript
利用node.js搭建简单web服务器的方法教程
2017/02/20 Javascript
Vue.js开发环境快速搭建教程
2017/03/17 Javascript
微信小程序实现图片轮播及文件上传
2017/04/07 Javascript
Vue响应式原理深入解析及注意事项
2017/12/11 Javascript
基于React Native 0.52实现轮播图效果
2020/08/25 Javascript
vue.js的双向数据绑定Object.defineProperty方法的神奇之处
2019/01/18 Javascript
Vue v-model组件封装(类似弹窗组件)
2020/01/08 Javascript
解决vue 使用axios.all()方法发起多个请求控制台报错的问题
2020/11/09 Javascript
centos下更新Python版本的步骤
2013/02/12 Python
python中的实例方法、静态方法、类方法、类变量和实例变量浅析
2014/04/26 Python
Python合并多个装饰器小技巧
2015/04/28 Python
Python2.x中文乱码问题解决方法
2015/06/02 Python
Django中使用Json返回数据的实现方法
2020/06/03 Python
Selenium 安装和简单使用的实现
2020/12/04 Python
使用 HTML5 Canvas 制作水波纹效果点击图片就会触发
2014/09/15 HTML / CSS
曼联官方网上商店:Manchester United Direct
2017/07/28 全球购物
波兰珠宝品牌:YES
2019/08/09 全球购物
三星法国官方网站:Samsung法国
2019/10/31 全球购物
局域网定义和特性
2016/01/23 面试题
青年文明号复核材料
2014/02/11 职场文书
幼儿园大班开学寄语
2014/08/02 职场文书
小学庆六一活动总结
2014/08/28 职场文书
员工年终考核评语
2014/12/31 职场文书
《悲惨世界》:比天空更广阔的是人的心灵
2020/01/16 职场文书
Spring Boot优化后启动速度快到飞起技巧示例
2022/07/23 Java/Android