VUEX 3 源码分析——4. 理解Action

好久不见了小伙伴们,今天继续发我的Vuex源码分析。

这段时间我现在已经做完了vuex和vue-router的源码分析笔记,不过还是按功能一节一节地来发吧。

另外我现在还在学习鱼皮大佬的《伙伴匹配系统》项目(但是后端使用Python-Flask实现),里面的一些知识狠狠地弥补了我技术上的不足(主要是因为我的工作是重业务的,反而偏基础的一些东西不是很熟)。

活不多说,开始理解vuex的action吧!

官网示例

  • 先看一下官网示例:

  • 在actions上定义函数,函数接受一个context对象,这个对象可以调用commit,state和getters。(官方说context对象不是store实例本身,等会看内部的实现源码就能更直观地感受到了)

  • action通过dispatch方法触发

  • 辅助函数 mapActions

  • 如果你看过我之前分析的两篇文章(Getter和Mutation),就能发现action的功能和getter,尤其是和mutation大同小异,只是action能进行异步操作嘛。那JavaScript里面,哪种语法适合异步操作能——当然是Promise啦。

  • 所以通过深入分析开源项目中的特定功能,我们可以洞察到项目背后的统一设计思想。

  • 理解这一设计思想不仅有助于我们掌握单个功能的具体实现,还能帮助我们预测和理解其他功能的设计模式。

  • 此外,阅读和学习优秀的开源项目,能够显著提升我们的代码理解能力和审美水平,从而在软件开发实践中,更好地应用这些设计原则和模式。

const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } }) store.dispatch('increment')

初始化Actions

  • 之前的Getter和Mutation初始化工作,都是在installModule函数中执行的,action也必然在此。

  • Store类初始化一个无原型链对象 this_actions:this._actions = Object.create(null)

  • 将用户定义的action按key-value格式,存储进 this._actions[key] 中,其中的每个key对应一个数组,数组中的元素为函数,每个函数都返回一个执行action的Promise

// store-util.js export function installModule(store, rootState, path, module, hot) { ... module.forEachAction((action, key) => { const type = action.root ? key : namespace + key; const handler = action.handler || action; registerAction(store, type, handler, local) }) } function registerAction(store, type, handler, local) { const entry = store._actions[type] || (store._actions[type] = []); entry.push(function wrappedActionHandler(payload) { const store_obj = { dispatch: local.dispatch, commit: local.commit, getters: local.getters, state: local.state, rootGetters: store.getters, rootSatte: store.state } // 这就是官方手册说的action函数接受的context对象不是store实例本身 let res = handler.call(store, store_obj, payload) // 如果res不是promise,将被封装在一个Promise对象中 if (!isPromise(res)) { res = Promise.resolve(res) } return res }) } // ./module/module.js export default class Module { ... forEachAction(fn) { if (this._rawModule.actions) { forEachValue(this._rawModule.actions, fn) } } }

实现dispatch方法

  • 在Store类上定义dispatch方法。将传入的参数格式化后,以Promise.all的方式调用 this._actions[type] 中的所有promise,返回一个新的Promise。

// ./store.js export class Store { ... dispatch(_type, _payload) { // unifyObjectStyle函数让 Actions 支持同样的载荷方式和对象方式进行分发 const {type, payload} = unifyObjectStyle(_type, _payload) const action = {type, payload} // 分发 sub action 用的 ... const result = entry.length > 1 ? Promise.all(entry.map(handler => handler(payload))) : entry[0](payload) return new Promise((resolve, reject) => { result.then(res => { ... // 插件的处理 resolve(res) }, error => { ... // 插件的处理 reject(error) }) }) } } // ./store-util.js export function unifyObjectStyle (type, payload, options) { if (isObject(type) && type.type) { options = payload payload = type type = type.type } return { type, payload, options } }

  • 最后将dispatch方法以类似隔离的方式,绑定store为 dispatch 的指定上下文。

  • 确保在不同的执行环境中调用dispatch时,它总是与创建它的store实例相关联。

// ./store.js export class Store { const store = this; const { dispatch, commit } = this; this.dispatch = function boundDispatch(type, payload) { return dispatch.call(store, type, payload) } }

mapActions 辅助函数

  • 实现方式和mapMutations一模一样,只是将commit换成了dispatch

// ./helper.js export const mapActions = normalizeNamespace((namespace, actions) => { const res = {} ... normalizeMap(actions).forEach(({ key, val }) => { res[key] = function mappedAction (...args) { // get dispatch function from store let dispatch = this.$store.dispatch ... return typeof val === 'function' ? val.apply(this, [dispatch].concat(args)) : dispatch.apply(this.$store, [val].concat(args)) } }) return res })

以上就是官网上Action的相关源码,下一遍会分析Module的实现源码。

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
zest
作者分享
最近业务需要,计划招多名短期兼职,时长半个月左右,做数据标注任务。 要求理解标注规则,(修改一下)按数量付钱,多劳多得,但是必须在某个规定时间内完成,需要有充足的时间。最好有标注经验。 可远程,有需要的结束后可开实习证明。 感兴趣的加我微信详谈。
7
有没有学习 Python 的鱼友,有用 Python 开发鱼皮项目的经验。 boss 上看了一堆都没匹配上,在这里随缘发一发。 应届或者毕业一年以内,计算机基础扎实,刷过题,有项目经验。 base 深圳南山区,薪资 15k-20k。 除了后端,还能接触到前端和大模型的方向,对职业发展非常有帮助。 感兴趣并且符合要求的加我微信 15773283322
5
新年伊始,招聘一名全栈(偏前端)工程师
5
站在面试官的角度,分析如何更好地应对面试
15
我又来招人了~ 这次是招一名实习生,做 AI 大模型 agent 应用开发。 基于上次招人的情况,我这里做了一些规定和要求,希望有意向的小伙伴能认真看完下面的内容并考虑清楚后再来投递简历。 岗位名称:大模型应用开发工程师 地点:深圳南山科技园 时间:至少实习3个月,周末双休 年限要求:应届实习 岗位要求: 1. 计算机相关专业,最好是大四或研二; 2. 熟悉 Python 语言,具有扎实的数据结构和算法功底; 3. 对基于AI大模型的应用开发感兴趣; 4. 时间比较充裕,能到公司坐班; 5. 良好的沟通能力、学习能力、和团队协作精神; 工作内容: 1. 基于大模型的 agent 应用开发; 2. 基于场景对 Prompt 进行设计和测评,提升大模型效果和稳定性; 3. 根据公司业务需求,与开发团队、产品运营团队紧密配置,持续改进应用; 感兴趣的小伙伴可以添加我微信 15773283322 --------------------------------------------------------------- 随便说一下,上次发布的招聘,也成功地在编程导航上找到了满意的候选人,目前已经入职半个月多了。 上次招人收到了很多人的简历,但是就简历质量而言,真的是一言难尽。 这周末我找时间输出一篇站在面试官的角度看待招聘过程的感受,写一些对焦虑难找工作的人的一些建议。 这里提一句就是真的要好好准备简历啊!
9
下载 APP