vue中⽤asyncawait来处理异步操作
昨天看了⼀篇vue的教程,作者⽤async/ await来发送异步请求,从服务端获取数据,代码很简洁,同时async/await 已经被标准化,也是需要学习⼀下了。
先说⼀下async的⽤法,它作为⼀个关键字放到函数前⾯,
async function timeout() {
  return 'hello world';
}
只有⼀个作⽤, 它的调⽤会返回⼀个promise 对象。调⽤⼀下看看就知道了,怎么调⽤?async 函数也是函数,所以它的调⽤和普通函数的调⽤没有什么区别,直接加括号调⽤就可以了,为了看结果,console.log ⼀下
async function timeout() {
return 'hello world'
}
console.log(timeout());
看⼀下控制台
async函数(timeout)的调⽤,确实返回promise 对象,并且Promise 还有status和value,如果async 函数中有返回值 ,当调⽤该函数时,内部会调⽤Promise.solve() ⽅法把它转化成⼀个promise 对象作为返回, 但如果timeout 函数内部抛出错误呢?async function timeout() {
throw new Error('rejected');
}
console.log(timeout());
就会调⽤ject() 返回⼀个promise 对象,
那么要想获取到async 函数的执⾏结果,就要调⽤promise的then 或catch 来给它注册回调函数,
async function timeout() {
return 'hello world'
}
timeout().then(result => {
console.log(result);
})
如果async 函数执⾏完,返回的promise 没有注册回调函数,⽐如函数内部做了⼀次for 循环,你会发现函数的调⽤,就是执⾏了函数体,和普通函数没有区别,唯⼀的区别就是函数执⾏完会返回⼀个promise 对象。
async function timeout() {
for (let index = 0; index < 3; index++) {
console.log('async '+ index);
}
}
console.log(timeout());
console.log('outer')
async 关键字差不多了,最重要的就是async函数的执⾏会返回⼀个promise 对象,并且把内部的值进⾏promise的封装。如果promise对象通过then或catch⽅法⼜注册了回调函数,async函数执⾏完以后,注册的回调函数就会放到异步队列中,等待执⾏。如果只是async, 和promise 差不多,但有了await就不⼀样了, await 关键字只能放到async 函数⾥⾯,await是等待的意思,那么它等待什么呢,它后⾯跟着什么呢?其实它后⾯可以放任何表达式,不过我们更多的是放⼀个返回promise 对象的表达式,它等待的是promise 对象的执⾏完毕,并返回结果
现在写⼀个函数,让它返回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, 我们可以看到,写异步代码就像写同步代码⼀样了,再也没有回调地域了。
这⾥强调⼀下等待,当js引擎在等待promise resolve 的时候,它并没有真正的暂停⼯作,它可以处理其它的⼀些事情,如果我们在testResult函数的调⽤后⾯,console.log ⼀下,你发现后⾯console.log的代码先执⾏。
async function testResult() {
let first = await doubleAfter2seconds(30);
let second = await doubleAfter2seconds(50);
let third = await doubleAfter2seconds(30);
console.log(first + second + third);
}
testResult();
console.log('先执⾏');
再写⼀个真实的例⼦,我原来做过⼀个⼩功能,话费充值,当⽤户输⼊电话号码后,先查这个电话号码所在的省和市,然后再根据省和市,到可能充值的⾯值,进⾏展⽰。
为了模拟⼀下后端接⼝,我们新建⼀个node 项⽬。新建⼀个⽂件夹 async, 然后npm init -y 新建package.json⽂件,npm install express --save 安装后端依赖,再新建server.js ⽂件作为服务端代码, public⽂件夹作为静态⽂件的放置位置,在public ⽂件夹⾥⾯放index.html ⽂件,整个⽬录如下
server.js ⽂件如下,建⽴最简单的web 服务器
const express = require('express');
const app = express();// express.static 提供静态⽂件,就是html, css, js ⽂件
app.use(express.static('public'));
app.listen(3000, () => {
console.log('server start');
})
再写index.html ⽂件,我在这⾥⽤了vue构建页⾯,⽤axios 发送ajax请求,为了简单,⽤cdn 引⼊它们。 html部分很简单,⼀个输⼊框,让⽤户输⼊⼿机号,⼀个充值⾦额的展⽰区域, js部分,按照vue 的要求搭建了模版
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Async/await</title>
<!-- CDN 引⼊vue 和 axios -->
<script src="cdn.jsdelivr/npm/vue"></script>
<script src="unpkg/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<!-- 输⼊框区域 -->
<div >
<input type="text" placeholder="请输⼊电话号码" v-model="phoneNum">
<button @click="getFaceResult">确定</button>
</div>
<!-- 充值⾯值显⽰区域 -->
<div>
充值⾯值:
<span v-for="item in faceList" :key='item'>
{{item}}
</span>
</div>
</div>
<!-- js 代码区域 -->
<script>
new Vue({
el: '#app',
data: {
phoneNum: '12345',
faceList: ["20元", "30元", "50元"]
},
methods: {
getFaceResult() {
}
}
})
</script>
</body>
</html>
现在我们来动态获取充值⾯值。当点击确定按钮时,我们⾸先要根据⼿机号得到省和市,所以写⼀个⽅法来发送请求获取省和市,⽅法命名为getLocation, 接受⼀个参数phoneNum , 后台接⼝名为phoneLocation,当获取到城市位置以后,我们再发送请求获取充值⾯值,所以还要再写⼀个⽅法getFaceList, 它接受两个参数, province 和city, 后台接⼝为faceList,在methods 下⾯添加这两个⽅法getLocation, getFaceList
methods: {
//获取到城市信息
getLocation(phoneNum) {
return axios.post('phoneLocation', {
phoneNum
})
},
// 获取⾯值
getFaceList(province, city) {
return axios.post('/faceList', {
province,
city
})
},
// 点击确定按钮时,获取⾯值列表
getFaceResult () {
}
}
现在再把两个后台接⼝写好,为了演⽰,写的⾮常简单,没有进⾏任何的验证,只是返回前端所需要的数据。Express 写这种简单的接⼝还是⾮常⽅便的,在app.use 和app.listen 之间添加如下代码
// 电话号码返回省和市,为了模拟延迟,使⽤了setTimeout
app.post('/phoneLocation', (req, res) => {
setTimeout(() => {
res.json({
success: true,
obj: {
province: '⼴东',
city: '深圳'
}
})
}, 1000);
})
// 返回⾯值列表
app.post('/faceList', (req, res) => {
setTimeout(() => {
res.json(
{
success: true,
obj:['20元', '30元', '50元']
}
)
}, 1000);
})
最后是前端页⾯中的click 事件的getFaceResult, 由于axios 返回的是promise 对象,我们使⽤then 的链式写法,先调⽤getLocation⽅法,在其then⽅法中获取省和市,然后再在⾥⾯调⽤getFaceList,再在getFaceList 的then⽅法获取⾯值列表,    // 点击确定按钮时,获取⾯值列表
getFaceResult () {
.then(res => {
if (res.status === 200 && res.data.success) {
let province = res.data.obj.province;
let city = res.data.obj.city;
.then(res => {
if(res.status === 200 && res.data.success) {
this.faceList = res.data.obj
}
await和async使用方法
})
}
})
.catch(err => {
console.log(err)
})
}
现在点击确定按钮,可以看到页⾯中输出了从后台返回的⾯值列表。这时你看到了then 的链式写法,有⼀点回调地域的感觉。现在我们在有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;
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);
}
}
现在把服务器停掉,可以看到控制台中输出net Erorr,整个程序正常运⾏。
以上这篇vue中⽤ async/await 来处理异步操作就是⼩编分享给⼤家的全部内容了,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。

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