Vue学习笔记(十二)
async与await
1. async
- async作为一个关键字放到声明函数前面,表示该函数为一个异步任务,不会阻塞后面函数的执行
- async函数里如果有异步过程会等待,但async函数本身会马上返回,不会阻塞当前线程。可以简单认为async函数工作在主线程,同步执行,不会阻塞界面渲染;async函数内部由await修饰的异步过程,工作在相应的协程上,会阻塞等待异步任务的完成再返回
- async函数返回类型为Promise对象
async函数会返回一个promise,并且Promise对象的状态值是resolved(成功的)
如果没有在async函数中写return,那么Promise对象resolve的值就是是undefined
如果写了return,那么return的值就会作为成功的时候传入的值
这是和普通函数本质上不同的地方,也是使用时重点注意的地方:
1. return new Promise(),这个符合async函数本意
2. return data 这是同步函数的写法,特别注意这其实就相当于Promise.resolve(data);还是一个Promise对象,但在调用async函数的地方通过简单的等号操作(=)是拿不到这个data的,因为返回值是一个Promise对象,所以需要用then(data => { })才可以拿到data
3. 如果没有返回值,相当于返回了Promise.resolve(undefined);
<script>
const aa = async () => {
return 1
//return Promise.resolve(1)
// return new Promise((resolve, reject) => {
// resolve(1)
// })
}
const bb = async () => {
return Promise.resolve(1)
// return new Promise((resolve, reject) => {
// resolve(1)
// })
}
//aa() 返回结果是 Promise对象
console.log(`output->aa()`,aa())
//获取异步函数的返回值
aa().then(res => {
console.log(`output->res`,res)
})
</script>
- 无等待
在没有await的情况下执行async函数,它会立即执行,返回一个Promise对象,并且不会阻塞后面的语句,这和普通返回Promise对象的函数并无二致
2. await
- await只能在async函数内部使用:不能放在普通函数里面,否则会报错
- await关键字后面跟Promise对象:在Pending状态时,相应的协程会交出控制权,进入等待状态,这是协程的本质
- await是async wait的意思: wait的是resolve(data)的消息,并把数据data返回,比如下面代码中,当Promise对象由Pending变为Resolved的时候,变量a就等于data,然后再顺序执行下面的语句console.log(a),这真的是等待,真的是顺序执行,表现和同步代码几乎一模一样
const a = await new Promise((resolve, reject) => {
// async process ...
return resolve(data);
});
console.log(a);
- await后面也可以跟同步代码: 不过系统会自动将其转化成一个Promsie对象
const a = await 'hello world'
// 相当于
const a = await Promise.resolve('hello world');
// 跟同步代码是一样的,还不如省事点,直接去掉await关键字
const a = 'hello world';
- await对于失败消息的处理: await只关心异步过程成功的消息resolve(data),拿到相应的数据data,至于失败消息reject(error),不关心不处理;对于错误的处理有以下几种方法供选择:
- 让await后面的Promise对象自己catch
- 也可以让外面的async函数返回的Promise对象统一catch
- 像同步代码一样,放在一个try…catch结构中
async function fetchData() {
// 将异步和同步的代码放在一个try..catch中,异常都能抓到
try {
const array = null;
let data = await asyncFn(); // 这里用await关键字,就能拿到结果值;否则,没有await的话,只能拿到Promise对象
if (array.length > 0) { // 这里会抛出异常,下面的catch也能抓到
array.push(data);
}
} catch (error) {
console.log(error);
}
}
document.addEventListener('DOMContentLoaded', fetchData);
- await对于结果的处理: await是个运算符,用于组成表达式,await表达式的运算结果取决于它等的东西,如果它等到的不是一个Promise对象,那么await表达式的运算结果就是它等到的东西;如果它等到的是一个Promise对象,await就忙起来了,它会阻塞其后面的代码,等着Promise对象resolve,然后得到resolve的值,作为await表达式的运算结果;虽然是阻塞,但async函数调用并不会造成阻塞,它内部所有的阻塞都被封装在一个Promise对象中异步执行,这也正是await必须用在async函数中的原因
3. 综合案例
<script>
// 模拟一个异步操作函数
const myPromise1 = () => {
return new Promise((resolve, reject) => {
console.log(`output->创建myPromise1`)
// 模拟一个异步操作,2秒钟后将结果返回
setTimeout(() => {
const random = Math.random()
if (random > 0.5) {
resolve(`myPromise1成功`);
} else {
reject(`myPromise1失败`)
}
}, 2000)
})
}
// 模拟一个异步操作函数
const myPromise2 = () => {
return new Promise((resolve, reject) => {
console.log(`output->创建myPromise2`)
// 模拟一个异步操作,2秒钟后将结果返回
setTimeout(() => {
const random = Math.random()
if (random > 0.5) {
resolve(`myPromise2成功`);
} else {
reject(`myPromise2失败`)
}
}, 2000)
})
}
// 模拟一个异步操作函数
const myPromise3 = () => {
return new Promise((resolve, reject) => {
console.log(`output->创建myPromise3`)
// 模拟一个异步操作,2秒钟后将结果返回
setTimeout(() => {
const random = Math.random()
if (random > 0.5) {
resolve(`myPromise3成功`);
} else {
reject(`myPromise3失败`)
}
}, 2000)
})
}
const myAsync = async () => {
try {
console.log(`myAsync开始执行`)
//await 同步执行代码获取Promise的resolve结果
const data1 = await myPromise1()
const data2 = await myPromise2()
const data3 = await myPromise3()
return `myAsync执行成功`
} catch (error) {
//await 执行出现错误处理(包括Promise的reject结果)
console.log(`myAsync执行出错:`, error)
}
}
//myAsync函数是async异步的 返回结果是Promise对象
myAsync().then((res) => {
console.log(`output->res`, res)
}).catch((error) => {
console.log(`output->error`, error)
})
</script>