记一次 Promise 数据传递中的 return 坑
前言#
熟悉的 Promise 语法的都知道,Promise的then、catch方法可以使用链式操作,在then的链式操作中,前面操作返回的值是可以被后面的操作所获取到的。
如下代码:
const result = new Promise(// ...)
result
.then(data => {
console.log(data)
// ....
return data.a
})
.then(data => {
console.log(data) // data.a
})最近在写 Vue 代码时,写了一个 Promise 的封装函数,专门用来处理 Axios 请求过来的数据。
// api/index.js
const handleRequest = request => {
return new Promise((resolve, reject) => {
request
.then(res => {
// ...
})
.catch(err => {
// ...
})
})
}
export default {
getData() {
return handleRequest(axios.get(// ...))
}
}分析#
因为有用Vuex来管理数据,为了方便,我把关于数据请求的操作全部放在 store 的 actions 中。
然后 Axios 请求过来的数据,分别需要有下面三种处理情况:
- 把一些数据保存到 store 里,这些数据后面 Vue 组件会用到。
- 不需要把数据到 store 中(后端只操作了数据库的数据,传给前端一个成功状态或者失败消息即可),但是有时候前端需要根据请求过来的状态(status)和消息(msg)的不同,作出一些不同的操作,比如提醒、跳转页面等。当然,有时候也会完全不用操作,比如账户登出。
- 既要保存数据,又要传出相应的状态或者消息提示给 Vue 组件进行实时交互操作。
代码#
- 对于第一种情况,非常简单,把数据
commit到 mutations 的函数方法中,然后再保存到 state 中就行了。后面 Vue 组件就可以通过mapGetters或者mapState语法糖调用这些数据。
// actions.js
import api from '../api'
export const getData =({commit}, params)=> {
api.getData(params) // 这里可以不需要使用 return,因为没有后续操作了
.then(data => {
commit(//...)
})
}- 对于第二种情况,更简单,直接返回
api.js的函数就行了,然后 Vue 组件通过mapActions语法糖就可以使用 actions 的函数。
// actions.js
import api from '../api'
export const getData =()=> {
return api.getData() // 如果没有后续操作可以不用写 return
}- 对于第三种情况,则比前面两种情况稍微复杂点,需要把两种方法结合起来。一开始我是重新封装一个 Promise 函数传递出去的。
// actions.js
import api from '../api'
export const getData =({commit}, params)=> {
return new Promise((resolve, reject) => {
api.getData(params)
.then(data => {
// ...
commit(//...)
resolve(data)
})
.catch(err => {
// ...
reject(err)
})
})
}但是后面想起来,promise 的then方法是可以一层一层传递参数的,只需要把数据保存到 store 后,再把数据往下传就可以了,这样代码更少,更简单。于是修改了上面的代码:
// actions.js
import api from '../api'
export const getData =({commit}, params)=> {
api.getData(params)
.then(data => {
// ...
commit(//...)
return data
})
}但是发现 Vue 组件调用这个函数后,用then()完全获取不了return出来的data数据,获得的是undefined。这不科学啊,百思不得其解!!!
之后才发现:原来这里有一个坑,我是不是少写了什么?没错,就是return,一直以来我能不写 return 就不写 return 的,这次终于掉坑了。
正确的代码是这样的:
// actions.js
import api from '../api'
export const getData =({commit}, params)=> {
return api.getData(params) // 记得写上 return
.then(data => {
// ...
commit(//...)
return data
})
}这样 Vue 组件调用方法时,终于可以获得data数据了。
总结#
其实这是一个很简单的错误,在我们写函数时,需要确认函数中的代码只是执行代码,还是需要输出值。如果需要输出值,不要忘记了使用return!