vuex 源码分析(五) action 详解
action类似于mutation,不同的是Action提交的是mutation,而不是直接变更状态,而且action里可以包含任意异步操作,每个mutation的参数1是一个对象,可以包含如下六个属性:
commit ;当前命名空间对应的commit
dispatch ;当前命名空间对应的dispatch
state ;当前命名空间对应的state
getters ;当前命名空间对应的getters
rootState ;根模块的state
rootGetters ;根模块的getters
类似于mutation,创建Vuex.Store()仓库实例时可以通过actions创建每个action
我们也不能直接调用一个action,而是通过 store.dispatch来调用,dispatch可以带两个参数,如下:
type ;对应的action名
payload ;传入的参数
dispatch还有一种写法,就是传入一个对象即可,该对象可以带一个type参数,type指定为action的名称,整个对象会作为参数传递给action。注意:action里可以包含异步操作
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script src="https://unpkg.com/vuex@3.1.0/dist/vuex.js"></script>
</head>
<body>
<div id="app">
<p>{{no}}</p>
<button @click="test">测试</button>
</div>
<script>
const store = new Vuex.Store({
state:{no:100},
mutations:{
increment(state,payload){state.no+=payload.no;}
},
actions:{
increment({commit},info){
return new Promise(function(resolve,reject){ //action里返回一个Promise对象
setTimeout(function(){
commit('increment',info)
resolve('ok')
},500)
})
}
}
}) var app = new Vue({
el:"#app",
store,
computed:{
no(){return this.$store.state.no}
},
methods:{
test(){
this.$store.dispatch('increment',{no:100})
}
}
})
</script>
</body>
</html>
我们在action里不返回一个promise对象也可以,vuex内部会调用Promise.resolve自动将返回值转换为一个Promise对象
源码分析
writer by:大沙漠 QQ:22969969
在创建Vuex.Store()初始化时会执行installModule()安装根模块,和mutation相关的如下:
function installModule (store, rootState, path, module, hot) { //安装模块
/*略*/
module.forEachAction(function (action, key) { //遍历module模块的action对象,如果找到了,则执行这个匿名函数 参数1:每个action值 key:对应的键名
var type = action.root ? key : namespace + key; //对应的命名空间+key
var handler = action.handler || action; //获取对应的函数
registerAction(store, type, handler, local); //调用registerAction注册action
});
/*略*/
}
registerAction是用于注册action的,如下:
function registerAction (store, type, handler, local) { //注册action函数 store:Store实例 type:包含命名空间的action名 handler:函数 local:上下文相关的对象
var entry = store._actions[type] || (store._actions[type] = []); //如果store对象的_actions对应的type为空,则初始化为空数组
entry.push(function wrappedActionHandler (payload, cb) { //给store._actions push 进去一个匿名函数
var res = handler.call(store, { //该函数
dispatch: local.dispatch,
commit: local.commit,
getters: local.getters,
state: local.state,
rootGetters: store.getters,
rootState: store.state
}, payload, cb); //执行handler函数,上下文为store,参数1是个对象,参数2是payload数据,将返回值保存到res中
if (!isPromise(res)) { //如果res不是一个Promise
res = Promise.resolve(res); //则将它转换为Promise对象
}
if (store._devtoolHook) {
return res.catch(function (err) {
store._devtoolHook.emit('vuex:error', err);
throw err
})
} else {
return res
}
});
}
从这里我们可以看到每个action对应的参数1,就是这里执行的handler函数,传入的对象,返回值如果不是Promise对象,则调用Promise.resolve()将它转换为Promise对象
等我们去调用this.$store.dispatch('increment',{no:100})触发一个action时,首先会触发Store函数内重定义的dispatch,它会以当前Store函数对象为上下文继续执行Store原型上的dispatch函数,如下:
Store.prototype.dispatch = function dispatch (_type, _payload) { //派发一个action异步操作
var this$1 = this;
// check object-style dispatch
var ref = unifyObjectStyle(_type, _payload); //规范一下参数,返回一个对象,这里和commit调用的是一样的
var type = ref.type;
var payload = ref.payload;
var action = { type: type, payload: payload };
var entry = this._actions[type]; //尝试获取type类型的action
if (!entry) { //如果不存在则报错并返回
{
console.error(("[vuex] unknown action type: " + type));
}
return
}
try {
this._actionSubscribers
.filter(function (sub) { return sub.before; })
.forEach(function (sub) { return sub.before(action, this$1.state); });
} catch (e) {
{
console.warn("[vuex] error in before action subscribers: ");
console.error(e);
}
}
var result = entry.length > 1
? Promise.all(entry.map(function (handler) { return handler(payload); }))
: entry[0](payload); //执行该action,如果大于1则用Promise.all()
return result.then(function (res) {
try {
this$1._actionSubscribers
.filter(function (sub) { return sub.after; })
.forEach(function (sub) { return sub.after(action, this$1.state); });
} catch (e) {
{
console.warn("[vuex] error in after action subscribers: ");
console.error(e);
}
}
return res
})
};
最后返回的还是一个res,也就是Promise对象,这样就实现了异步操作了。
vuex 源码分析(五) action 详解的更多相关文章
- vuex 源码分析(六) 辅助函数 详解
对于state.getter.mutation.action来说,如果每次使用的时候都用this.$store.state.this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我 ...
- 【集合框架】JDK1.8源码分析之ArrayList详解(一)
[集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...
- nginx源码分析线程池详解
nginx源码分析线程池详解 一.前言 nginx是采用多进程模型,master和worker之间主要通过pipe管道的方式进行通信,多进程的优势就在于各个进程互不影响.但是经常会有人问道,n ...
- vuex 源码解析(四) mutation 详解
mutation是更改Vuex的store中的状态的唯一方法,mutation类似于事件注册,每个mutation都可以带两个参数,如下: state ;当前命名空间对应的state payload ...
- Golang源码分析之目录详解
开源项目「go home」聚焦Go语言技术栈与面试题,以协助Gopher登上更大的舞台,欢迎go home~ 导读 学习Go语言源码的第一步就是了解先了解它的目录结构,你对它的源码目录了解多少呢? 目 ...
- Tomcat源码分析 | 一文详解生命周期机制Lifecycle
目录 什么是Lifecycle? Lifecycle方法 LifecycleBase 增加.删除和获取监听器 init() start() stop() destroy() 模板方法 总结 前言 To ...
- Java 容器源码分析之集合类详解
集合类说明及区别 Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtable ├HashMap └W ...
- Cloudera Impala源码分析: SimpleScheduler调度策略详解包括作用、接口及实现等
问题导读:1.Scheduler任务中Distributed Plan.Scan Range是什么?2.Scheduler基本接口有哪些?3.QuerySchedule这个类如何理解?4.Simple ...
- VueX源码分析(5)
VueX源码分析(5) 最终也是最重要的store.js,该文件主要涉及的内容如下: Store类 genericSubscribe函数 resetStore函数 resetStoreVM函数 ins ...
随机推荐
- MySQL 示例数据库
微软 SQL Server 自带了一些示例数据库,可用于练习和测试.也可作为自己数据库设计时的参考.这些示例数据库开源在了 GitHub,可在 Microsoft/sql-server-samples ...
- Javase之集合体系之(1)集合顶层类Collection与其迭代器知识
集合体系之集合顶层类Collection与其迭代器知识 集合的由来:Java是一门面向对象语言,而面向对象语言对事物的描述是通过对象体现的,为了方便对多个对象进行操作,就必须把多个对象进行存储,而要存 ...
- java.lang.IllegalArgumentException: java.util.zip.ZipException: invalid LOC header (bad signature)异常解决方法
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start com ...
- js 替换字符串中的双引号
text.replace(/\"/g, ''); 可根据此方法去掉字符串中的双引号
- 使用Wireshark进行DNS协议解析
- 域名及解析过程 域名由一系列 - DNS协议报文格式 一次DNS过程包含一对请求报文和响应报文.请求和响应报文有统一的报文格式如下图: - DNS报文例子 一次DNS请求的过程: 包括请求和响应, ...
- 【转载】每个 Android 开发者必须知道的消息机制问题总结
Android的消息机制几乎是面试必问的话题,当然也并不是因为面试,而去学习,更重要的是它在Android的开发中是必不可少的,占着举足轻重的地位,所以弄懂它是很有必要的.下面就来说说最基本的东西. ...
- [Go] 利用channel形成管道沟通循环内外
这个要解决的问题是,比如如果有一个大循环,取自一个大的文件,要进行逻辑处理,那么这个逻辑的代码要放在循环每一行的循环体里面,这样有可能会出现一个for循环的逻辑嵌套,一层又一层,类似俄罗斯套娃.如果放 ...
- [视频教程] 包管理器方式安装使用openresty新手上路
OpenResty是一个通过Lua扩展Nginx实现的可伸缩的Web平台,内部集成了大量精良的Lua库.第三方模块以及大多数的依赖项.用于方便地搭建能够处理超高并发.扩展性极高的动态Web应用.Web ...
- 渗透测试学习 二十三、常见cms拿shell
常见cms 良精.科讯.动易.aspcms.dz 米拓cms.phpcms2008.帝国cms.phpv9 phpweb.dedecms 良精 方法: 1.数据库备份拿shell 上传图片——点击数据 ...
- CodeForces - 573A (简单数论+模拟)
题意 https://vjudge.net/problem/CodeForces-573A 有n个数ai ,你可以把每个数任意次×2 或×3 ,问能否最终使得每个数相等. 思路 x2和x3只能改变数 ...