参考文档:
异步请求在vue中的应用
- 封装一个基于superagent的异步请求方法:
export const _getRequest = function (url) {
const promise = request.get(url)
return new Promise((resolve, reject) => {
promise.end(function (err, resp) {
if (!err) {
resolve(resp)
} else {
reject(err)
}
})
})
}
- api中调用该方法
getUser: (id) => {
const url = 'http://xxx.com/api/get.php?' + id
return _getRequest(url)
}
- 页面调用请求
说明:调用getUser()方法来获取api数据,在try中得到响应数据,然后对数据进行处理,若其他地方要想直接使用getUser方法得到的数据,也可以将getUser得到的数据返回,但是调用此getUser方法时候必须加上await关键字,并且调用方法前必须也加上async关键字
注意:只有catch才能捕获到Promise.reject异常
created () {
this.init()
}
methods:
init () {
this.getUser(1)
}
async getUser (id) {
try {
let userinfo = await api.getUserApi(id)
// handle data
console.log(userinfo)
} catch (err) {
console.log(err) // 这里捕捉到错误 `error`
}
}
- 使用getUser返回数据的方法
基本规则:
* async 表示这是一个async函数,await只能用在这个函数里面。
* await 表示在这里等待promise返回结果了,再继续执行。
* await 后面跟着的应该是一个promise对象(当然,其他返回值也没关系,只是会立即执行,不过那样就没有意义了…)
说明:
如上面所描述,使用async关键字之后,可以在init方法中使用await来调用像getUser这样的异步请求方法返回的数据了, 因为getUser返回的是promise对象,所以我们使用await得到数据后才回向下执行。
created () {
this.init()
}
methods:
async getUser (1) {
try {
return await api.getUserApi(1)
} catch (err) {
console.log(err) // 这里捕捉到错误 `error`
}
}
async init () {
console.log('one')
let one = await this.getUser(1)
console.log('one data:', one)
if (!one) { // 当getUser异常时,返回undefined
return false
}
console.log('two')
let two = await this.getUser(2)
console.log('two data:', two)
}
- 将常用的get请求封装到公共的方法中,方便不同的页面调用
说明:一般只有在页面初始化时获取初始数据,并且是有先后关联的数据时会用到像同步那样的要求,所以我们只封装常用的get请求即可
sleep方法中可以将reject方法打开,注释resolve方法来模拟出错
可以在api目录下创建一个asyncGet.js文件
import api from './api'
export default{
sleep: (time) => {
return new Promise(function (resolve, reject) {
setTimeout(function () {
// 模拟出错了,返回 ‘error’
// reject('error')
resolve('ok')
}, time)
})
},
asyncSleep: async () => {
try {
return await this.a.sleep(1000)
} catch (err) {
console.log(err) // 这里捕捉到错误 `error`
}
},
asyncGetUser: async () => {
try {
return await api.getUser()
} catch (err) {
console.log(err) // 这里捕捉到错误 `error`
}
}
}
页面文件:
import asyncFun from '@/api/api/asyncGet'
async init () {
console.log('init')
let se = await asyncFunc.asyncSleep()
console.log('se:', se)
if (!se) {
return false
}
let user = await asyncFunc.asyncGetUser()
this.data.params = user
console.log(user)
this.$nextTick(() => {
console.log('bbb')
})
}
async init () {
console.log('one')
let one = await asyncFun.asyncSleep()
console.log('one data:', one)
if (!one) { // 当getUser异常时,返回undefined
return false
}
console.log('two')
let two = await asyncFun.asyncGetUser()
console.log('two data:', two)
}
封装异步获取api方法
// 定义方法
asyncGetUser: () => {
try {
const url = 'http://xxx.com/api/get.php'
return _getRequest(url)
} catch (err) {
console.log(err) // 这里捕捉到错误 `error`
}
}
// 调用
调用上面的方法时,返回的结果说明
try,返回Promise对象,接收处一定要用await,调用函数的函数前必须加上async,这样才能获取到返回的数据
catch 无返回,调用处接受到undefined, 可以用if来判断下一步动作
// async 方法
export const _getRequest = function (url) {
if (uaFlag()) {
const promise = request.get(url)
.use(setShcmpSignature)
.use(apiPrefix)
return new Promise((resolve, reject) => {
promise.end(function (err, resp) {
if (!checkRequest(resp)) { //在这里判断status,不用在每次调用时判断
reject(err)
} else {
resolve(resp.body)
}
})
})
}
}
async文件
async.listStoreApps()返回的是Promise对象。使用async/await可执行同步处理,then/catch方法可执行异步处理。
1. 同步处理
1.1 将获取_getRequest()方法放到try中捕获正确信息,返回的任然是Promise对象,catch中不做返回,调用处接收到undefined,可以用if来判断下一步动作
listStoreApps: () => {
try {
let url = joinURL('stores')
return _getRequest(url)
} catch (err) {
console.log(err)
}
}
1.2使用
methods: {
async getList () {
let a = await async.listStoreApps()
console.log(a)
... // 可以有多个调用,注意必须加上await关键字
}
}
2.异步处理
2.1 将获取_getRequest
listStoreApps: () => {
let url = joinURL('apps')
return _getRequest(url)
}
2.2 使用
上一步返回的是Promise对象,可以使用then/catch来做异步处理
其实可以使用1.1中的方法来处理,但是,try中抛出异常时,返回的是undefined,下面的方法只能进入then中进行处理。而如果要try/catch的catch有返回,那try/catch就没有使用的意义了。
methods: {
getList () {
async.listStoreApps().then(function (result) {
console.log(result)
}).catch(function (err) {
console.log(err)
})
}
// getList1 () {}, ... 多个这样的方法可以异步执行
}
3. 两种方法混合使用
一般,页面处理数据都是异步执行的,偶尔会遇到同步执行的时候,当页面初始化时,会先获取初始数据,这时就会有同步获取数据的需求。
3.1 async中
listStoreApps: () => {
let url = joinURL('apps')
return _getRequest(url)
}
3.2 页面中使用
methods: {
// 异步调用, 需要多一步try捕获数据的方法
listStoreApps () {
try {
return async.listStoreApps()
} catch (err) {
console.log(err)
}
}
async getList () {
let res1 = await this.listStoreApps()
if (res1) {
...
}
console.log(res1)
}
// 同步调用,和上面2.2方法同样
getList () {
async.listStoreApps().then(function (result) {
console.log(result)
}).catch(function (err) {
console.log(err)
})
}
},
}
vue中使用Promise.all()实例
methods: {
getInitData () {
this.loading = true
let apis = [
this.aaa(),
api.listClusters(),
api.listRegistries(true)
]
Promise.all(apis).then(res => {
let [aaa, clusterList, registryList] = res
console.log(aaa) // ok
this.dealClusterList(clusterList)
this.dealRegistryList(registryList)
this.loading = false
}).catch(err => {
console.log('err: ', err)
this.loading = false
})
},
aaa () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
// 模拟出错了,返回 ‘error’
// reject('error')
resolve('ok')
}, 3000)
})
},
dealClusterList (clusterList) {
if (clusterList && clusterList.items) {
this.$store.dispatch('listClusters', clusterList.items)
}
},
dealRegistryList (registryList) {
if (registryList && registryList.registries) {
this.$store.commit('setCommonRegistries', registryList.registries)
}
}
}
Promise.all()也可以放到一个异步中调用
asyncGetInit () {
try {
await api.getOwnPolicies()
} catch (err) {
console.log('err: ', err)
}
},
async asyncGetInit () {
try {
return await Promise.all([
api.listOrgs(),
api.getOwnPolicies()
])
} catch (err) {
console.log('err: ', err)
}
},
async getInitData () {
this.$store.commit('setLoading', true)
let policyRes = await this.asyncGetInit()
if (!policyRes) {
return
console.log('获取信息失败')
}
let initData = await this.asyncGetInit()
// 出错时返回 undefined
if (!initData) {
return
console.log('获取数据失败')
}
let [orgList, policyList] = initData
this.dealOrgList(orgList)
this.dealGetOwnPolicies(policyList)
this.$store.commit('setLoading', false)
},