为什么要用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>
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值