Vuex入门(5)—— 为什么要用Action管理异步操作

Action 类似于 mutation,不同在于:

1.Action 提交的是 mutation,而不是直接变更状态。

2.Action 可以包含任意异步操作。

官方给的定义我没什么意见,事实上我通过mutation异步操作,好像跟用action管理也没什么区别。关于为什么要用Action管理异步操作,我会通过一个简单的例子和一个复杂的例子来进行说明,事实上,如果初学者没有考虑到实际场景的复杂情况,会觉得Action根本没有一点软用,这个时候就要把问题想得复杂一些了,然后才能看到Action的作用。

先来看一个简单的例子,也是我对如果不用Action进行异步操作的一些初步探索。

第一步:我非常作死的重写了mutation状态管理器中对状态操作的一些写法,我使用了异步操作代替了之前的操作。

// mutation.js
const increment = (state) => {
  setTimeout(() => {
    state.count++
  }, 1000)
}
const decrement = (state) => {
  setTimeout(() => {
    state.count--
  }, 2000)
  state.count--
}
export {increment, decrement}

第二步:试验一下能否成功

<template>
  <div>
    <button @click="decrement">-</button>
    <span>{{count}}</span>
    <button @click="increment">+</button>
  </div>
</template>
<script>
import { mapState, mapMutations} from ‘vuex‘
export default {
  computed: {
    ...mapState([‘count‘])
  },
  methods: {
    ...mapMutations([‘increment‘, ‘decrement‘]),
  }
}
</script>

<style>

</style>

第三步:发现除了每次操作加减时候有一秒的延时,不管你怎么操作,结果都是正确的,是符合社会主义核心价值观的。

第四步:用Action处理异步操作(先得把之前作死改掉的mutation的代码改回来)

// 正常的mutation
const increment = (state) => {
  state.count++
}
const decrement = (state) => {
  state.count--
}
export {increment, decrement}
// action.js处理一些异步操作

// Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象
let incrementAsync = (content) => {
setTimeout(() => {
content.commit(‘increment‘)
}, 1000)
}
let decrementAsync = (content) => {
setTimeout(() => {
content.commit(‘decrement‘)
}, 1000)
}
export {incrementAsync, decrementAsync}
<template>
  <div>
    <button @click="decrementAsync">-</button>
    <span>{{count}}</span>
    <button @click="incrementAsync">+</button>
  </div>
</template>
<script>
import { mapState, mapMutations, mapActions } from ‘vuex‘
export default {
  computed: {
    ...mapState([‘count‘])
  },
  methods: {
    ...mapMutations([‘increment‘, ‘decrement‘]),
    ...mapActions([‘incrementAsync‘, ‘decrementAsync‘]) //这里用了辅助函数,不了解的可以看这个系列的第二篇文章
  }
}
</script>

<style>

</style>

第五步:测试一下效果,你会感觉跟没有用action直接用mutation的结果一毛一样。再看一下官网说明。

所以,官网说的这句话有问题?
 确实有问题,因为在mutation中执行异步操作并不会报错,也能正确更改状态,所以并不是所谓的“必须同步执行”这么苛刻,只能说你最好不要这么做。(这里说一句题外话,我初学vuex的时候,大概去年,在mutaition中一旦有异步操作,控制台立马就会有警告,不知道是记错了还是现在删除了这个设定)

上面的例子可能太过简单,以至于Action看起来都发挥不了什么作用。

下面来看一个复杂的例子,这个例子有助于理解为什么要用Action管理异步操作
需求如下

state中存储了一个状态,我们还是复用刚才的count

现在有两个异步操作,他们都能改变count的值

第二个异步操作的条件依赖第一个异步操作的结果,比如第一个异步操作执行了count ++ ,count :0 = >1,第二个异步操作会先判断当前count的值,if(count === 1) { do something...} else { do something... }

当异步操作涉及互相依赖的情况的时候,我们肯定希望被依赖的操作执行完成之后,再执行依赖项,这样能保证程序执行得到正确的结果,但异步操作,如接口访问这种,往往是不能确定执行完成的时间的,

通常你在接口A中得到一个值,a

接口B需要使用这个值结合B接口返回的值进行一些判断操作,if(a&&b){ ... }

这个时候如果B接口执行完毕了,A接口的值还没过来的话,就可能得到错误的结果。 a => undefined

所以这里牵扯到了一个异步操作的顺序执行问题,既然是异步操作问题,基本都会用到ES6的promise函数去解决,有兴趣的可以用看一下我的文章——关于promise的一些使用和原理。

下面我们重写一下代码

// Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象
let incrementAsync = (content) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      content.commit(‘increment‘)
      resolve()
    }, 1000)
  })
}
let decrementAsync = (content) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      content.commit(‘decrement‘)
      resolve()
    }, 1000)
  })
}
export {incrementAsync, decrementAsync}
})
<template>
  <div>
    <button @click="dec">-</button>
    <span>{{count}}</span>
    <button @click="add">+</button>
  </div>
</template>
<script>
import { mapState, mapMutations, mapActions } from ‘vuex‘
export default {
  computed: {
    ...mapState([‘count‘])
  },
  methods: {
    ...mapMutations([‘increment‘, ‘decrement‘]),
    ...mapActions([‘incrementAsync‘, ‘decrementAsync‘]),
    add () {
      this.incrementAsync().then(() => {
        this.increment()
      })
    },
    dec () {
      this.decrementAsync().then(() => {
        // do something
      })
    }
  }
}
</script>

<style>

</style>

关于Action,细枝末节的东西并不想多讲,比如action中的‘载荷’,mapAction辅助函数,promise()函数使用等等,都是之前讲过的,写这篇文章的目的还是想重申一下为什么要用Action管理异步操作,有些人可能觉得如果一种代码可以用另一种看起来可以实现的方式实现的话,就不用去管“规范”的问题了,反而觉得这看起来更像一个“黑客”的做法,从而刻意的追求程序的“自由性”。

我只能说,你可以这么做,但请你善待帮你维护代码的人,因为你的“自由开发”可能让别人完全搞不懂你在写什么,只想骂你是个傻X。

原文地址:https://www.cnblogs.com/xtjatswc/p/10325175.html

时间: 2024-10-15 01:06:13

Vuex入门(5)—— 为什么要用Action管理异步操作的相关文章

Vuex入门

在 vue 开发中,组件通信一直是一大痛点. 当项目是很简单的 SPA 或者多入口项目时,可以靠着 vue 自带的 prop/$emit 进行组件通信:规模再大一些,可以搭配使用 bus 总线进行兄弟组件通信:项目再大一些,出现更复杂的组件关系时,复杂的组件通信可以让你写得怀疑人生. 万幸的是, vue 官方出品了 vuex ,通过全局式的状态管理,解决了这一痛点. 虽然 vuex 很好用,但是,很多小伙伴和我吐槽 vuex 的文档和 vue-ssr 的文档一样,让人看得一脸懵逼. 好吧,下面就

untiy3d action管理机制的编写

使用unity3d对于一些可视化强迫者来说,是一个不错的选择,但unity3d没有cocos2d的action管理机制,比如cocos2dx的CCMoveTo,CCScale等action,所以笔者通过封装action管理来实现类似cocos2dx的actionmanager. 首先需要写一个ActionManager来创建.更新.移除所有action.编写代码实现如下: using UnityEngine;using System.Collections;using System; publi

Cocos2d-x 3.4 Action管理(ActionManager)总结

Cocos2d-x Action管理 动作管理类CCActionManager是一个管理所有动作的单例,工作原理是:当CCNode执行runAction时,该函数会把动作通过动作管理类的addAction函数将对象传递给CCActionManager的单例,该实例再把这个动作添加到自己的动作序列中. 动作管理单例通过定时刷新自己的update方法,在这个方法中去调用行为序列中每个动作的step(暂停的行为不会update),这些step方法再根据自身的完成进度去update或是结束行为. 实际上

Android基础入门教程——10.9 WallpaperManager(壁纸管理器)

Android基础入门教程--10.9 WallpaperManager(壁纸管理器) 标签(空格分隔): Android基础入门教程 本节引言: 本节给大家带来的是WallpaperManager(壁纸管理器),如其名,就是手机壁纸相关的 一个API,在本节中我们会描述下WallpaperManager的基本用法,调用系统自带的 壁纸选择功能,将Activity的背景设置为壁纸背景,以及写一个定时换壁纸的例子~ 好了,不BB,开始本节内容~ 官方API文档:WallpaperManager 1

ASP.NET MVC 入门4、Controller与Action

原帖地址:http://www.cnblogs.com/QLeelulu/archive/2008/10/04/1303672.html Controller是MVC中比较重要的一部分.几乎所有的业务逻辑都是在这里进行处理的,并且从Model中取出数据.在ASP.NET MVC Preview5中,将原来的Controller类一分为二,分为了Controller类和ControllerBase类.Controller类继承自ControllerBase类,而ControllerBase实现是了

Android基础入门教程——10.1 TelephonyManager(电话管理器)

Android基础入门教程--10.1 TelephonyManager(电话管理器) 标签(空格分隔): Android基础入门教程 本节引言: 本章节是Android基础入门教程的最后一章,主要讲解是一些零零散散的一些知识点,以及一些遗漏 知识点的补充,这些零散的知识点包括,各种系统服务的使用,比如本节的电话管理器,短信管理器, 振动器,闹钟,壁纸等等,还有传感器之类的东西!乱七八糟什么都有哈!好的,本节我们要学习的 是TelephonyManager,见名知义:用于管理手机通话状态,获取电

Android官方入门文档[6]添加Action按钮

Android官方入门文档[6]添加Action按钮 Adding Action Buttons添加Action按钮 This lesson teaches you to1.Specify the Actions in XML2.Add the Actions to the Action Bar3.Respond to Action Buttons4.Add Up Button for Low-level Activities You should also read?Providing Up

Vuex 模块化实现待办事项的状态管理

在vue里,组件之间的作用域是独立的,父组件跟子组件之间的通讯可以通过prop属性来传参,但是在兄弟组件之间通讯就比较麻烦了.比如A组件要告诉一件事给B组件,那么A就要先告诉他们的爸组件,然后爸组件再告诉B.当组件比较多,要互相通讯的事情很多的话,爸组件要管他们那么多事,很累的.vuex正是为了解决这个问题,让多个子组件之间可以方便的通讯. 原文作者:林鑫,作者博客:https://github.com/lin-xin/blog 项目介绍 待办事项中的一个事件,它可能拥有几个状态,未完成.已完成

Vue2.0 探索之路——vuex入门教程和思考

Vuex是什么 首先对于 vuex 是什么,我先引用下官方的解释. Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 就我的直观理解 vuex 类似于维护了一个全局的 Map对象.你可以往里存放 key-value .然后所有的state数据操作都方法化,保证操作的可追踪和数据的干净. Vuex应用场景 其实对于vuex的应用场景一开始我有点误区,因为我把它当做了一个从始至终类似于 loc