asyncawait基本理解及项⽬案例(结合Promise)
ES2017 标准引⼊了 async 函数,使得异步操作变得更加⽅便。
1.async/await场景
这是⼀个⽤同步的思维来解决异步问题的⽅案,当前端接⼝调⽤需要等到接⼝返回值以后渲染页⾯时。
2.名词解释
async
async的⽤法,它作为⼀个关键字放到函数前⾯,⽤于表⽰函数是⼀个异步函数,因为async就是异步的意思, 异步函数也就意味着该函数的执⾏不会阻塞后⾯代码的执⾏,async 函数返回的是⼀个promise 对象,可以使⽤then⽅法添加回调函数。当函数执⾏的时候,⼀旦遇到await就会先返回,等到异步操作完成,再接着执⾏函数体内后⾯的语句。
await
await的含义为等待。意思就是代码需要等待await后⾯的函数运⾏完并且有了返回结果之后,才继续执⾏下⾯的代码。这正是同步的效果。
3.基本讲解
简单案例:
async function timeout() {
return 'hello world'
}
console.log(timeout());
console.log('虽然在后⾯,但是我先执⾏');
原来async 函数返回的是⼀个promise 对象,如果要获取到promise 返回值,我们应该⽤then ⽅法, 继续修改代码
async function timeout() {
return 'hello world'
}
timeout().then(result => {
console.log(result);
})
console.log('虽然在后⾯,但是我先执⾏');
我们获取到了"hello world',  同时timeout 的执⾏也没有阻塞后⾯代码的执⾏,和 我们刚才说的⼀致。
你可能注意到控制台中的Promise 有⼀个resolved,这是async 函数内部的实现原理。如果async 函数中有返回⼀个值 ,当调⽤该函数时,内部会调⽤solve() ⽅法把它转化成⼀个promise 对象作为返回,但如果timeout 函数内部抛出错误呢? 那么就会调⽤ject() 返回⼀个promise 对象, 这时修改⼀下timeout 函数
async function timeout(flag) {
if (flag) {
return 'hello world'
} else {
throw 'my god, failure'
}
}
console.log(timeout(true))  // 调⽤solve() 返回promise 对象。
console.log(timeout(false)); // 调⽤ject() 返回promise 对象。
如果函数内部抛出错误, promise 对象有⼀个catch ⽅法进⾏捕获。
timeout(false).catch(err => {
console.log(err)
})
await是等待的意思,那么它等待什么呢,它后⾯跟着什么呢?其实它后⾯可以放任何表达式,不过我们更多的是放⼀个返回promise 对象的表达式。注意await 关键字只能放到async 函数⾥⾯
现在写⼀个函数,让它返回promise 对象,该函数的作⽤是2s 之后让数值乘以2
// 2s 之后返回双倍的值
function doubleAfter2seconds(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2 * num)
}, 2000);
} )
}
现在再写⼀个async 函数,从⽽可以使⽤await 关键字, await 后⾯放置的就是返回promise对象的⼀个表达式,所以它后⾯可以写
上 doubleAfter2seconds 函数的调⽤
async function testResult() {
let result = await doubleAfter2seconds(30);
console.log(result);
}
现在调⽤testResult 函数
testResult();
打开控制台,2s 之后,输出了60.
现在我们看看代码的执⾏过程,调⽤testResult 函数,它⾥⾯遇到了await, await 表⽰等⼀下,代码就暂停到这⾥,不再向下执⾏了,它等什么呢?等后⾯的promise对象执⾏完毕,然后拿到promise resolve 的值并进⾏返回,返回值拿到之后,它继续向下执⾏。具体到 我们的代码, 遇到await 之后,代码就暂停执⾏了, 等待doubleAfter2seconds(30) 执⾏完毕,doubleAfter2seconds(30) 返回的
promise 开始执⾏,2秒 之后,promise resolve 了, 并返回了值为60, 这时await 才拿到返回值60, 然后赋值给result, 暂停结束,代码才开始继续执⾏,执⾏ console.log语句。
就这⼀个函数,我们可能看不出async/await 的作⽤,如果我们要计算3个数的值,然后把得到的值进⾏输出呢?
async function testResult() {
let first = await doubleAfter2seconds(30);
let second = await doubleAfter2seconds(50);
let third = await doubleAfter2seconds(30);
console.log(first + second + third);
}
6秒后,控制台输出220, 我们可以看到,写异步代码就像写同步代码⼀样了,再也没有回调地域了。
Vue项⽬案例
普通案例:
methods: {
getLocation(phoneNum) {
return axios.post('/mm接⼝', {
phoneNum
})
},
getFaceList(province, city) {
return axios.post('/nn接⼝', {
province,
city
})
},
getFaceResult () {
if (res.status === 200 && res.data.success) {
let province = res.data.obj.province;
let city = res.data.obj.city;
if(res.status === 200 && res.data.success) {
this.faceList = res.data.obj
}
})
}
}).catch(err => {
console.log(err)
})
}
}
这时你看到了then 的链式写法,有⼀点回调地域的感觉。现在我们在有async/ await 来改造⼀下。
async/ await案例:
⾸先把 getFaceResult 转化成⼀个async 函数,就是在其前⾯加async, 因为它的调⽤⽅法和普通函数的调⽤⽅法是⼀致,所以没有什么问题。然后就把 getLocation 和getFaceList 放到await 后⾯,等待执⾏, getFaceResult  函数修改如下:
async getFaceResult () {
let location = Location(this.phoneNum);
if (location.data.success) {
let province = location.data.obj.province;
let city = location.data.obj.city;
await和async使用方法
let result = FaceList(province, city);
if (result.data.success) {
this.faceList = result.data.obj;
}
}
}
现在代码的书写⽅式,就像写同步代码⼀样,没有回调的感觉,⾮常舒服。
现在就还差⼀点需要说明,那就是怎么处理异常,如果请求发⽣异常,怎么处理? 它⽤的是try/catch 来捕获异常,把await 放到 try 中进⾏执⾏,如有异常,就使⽤catch 进⾏处理。
async getFaceResult () {
try {
let location = Location(this.phoneNum);
if (location.data.success) {
let province = location.data.obj.province;
let city = location.data.obj.city;
let result = FaceList(province, city);
if (result.data.success) {
this.faceList = result.data.obj;
}
}
} catch(err) {
console.log(err);
}
}
Vue项⽬案例(封装)
http.js
'use strict'
import axios from 'axios'
import qs from 'qs'
quest.use(config => {
// loading
return config
}, error => {
ject(error)
})
sponse.use(response => {
return response
}, error => {
sponse)
})
function checkStatus (response) {
// loading
// 如果http状态码正常,则直接返回数据
if (response && (response.status === 200 || response.status === 304 || response.status === 400)) {
return response
// 如果不需要除了data之外的数据,可以直接 return response.data
}
// 异常状态下,把错误信息返回去
return {
status: -404,
msg: '⽹络异常'
}
}
function checkCode (res) {
// 如果code异常(这⾥已经包括⽹络错误,服务器错误,后端抛出的错误),可以弹出⼀个错误提⽰,告诉⽤户  if (res.status === -404) {
alert(res.msg)
}
if (res.data && (!res.data.success)) {
alert(_msg)
}
return res
}
export default {
post (data,url) {
return axios({
method: 'post',
url: url,
data: qs.stringify(data),
timeout: 10000,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'      }
}).then(
(response) => {
return checkStatus(response)
}
)
},
get (url, params) {
return axios({
method: 'get',
baseURL: '/api/v1',
url,
params, // get 请求时带的参数
timeout: 10000,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
}).then(
(response) => {
return checkStatus(response)
}
)
.then(
(res) => {
return checkCode(res)
}
)
}
}
api.js
export default {
getCode: '127.0.0.1:8888/.....'
}
auth.vue

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。