async函数
① 特点:
- 内置执行器
- 更好的语义
- 更广的适用性
- 返回值时Promise
② 基本用法
async函数返回一个Promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先去执行await后面的方法,当在执行方法时遇到异步操作时,先返回(即先return),然后再去执行异步操作。等到第一个await后的方法执行完毕后再执行后面的语句。
在下面例子中,先执行getName方法,在getName方法中遇到异步操作(即计时器),故先返回,即输出Promise对象(即输出getinfo()的返回值,但promiseValue值为null,等到所有语句执行完毕后,promiseValue值为所有Promise的值的集合)。再继续执行异步操作。等到getName方法执行完毕后再执行getSex方法,等到getSex方法执行完后再输出1111
输出:
function getName(){
const promise=new Promise(function (resolve,reject){
try{
console.log("hello1");
console.log("hello11");
setTimeout(function () {
console.log("计时器1");
resolve("张三")
console.log("计时器11");
},500);
}
catch(err){
reject(err)
}
});
return promise;
}
function getSex(){
const promise=new Promise(function (resolve,reject){
try{
console.log("hello2");
setTimeout(function () {
console.log("计时器2");
resolve("男")
},1000);
}
catch(err){
reject(err)
}
});
return promise;
}
async function getinfo(){
const name= await getName();
const sex=await getSex();
console.log(1111);
return {
name:name,
sex:sex
};
}
console.log(getinfo());
③ 语法以及Promise对象的状态变化
- async函数返回一个Promsie对象(无论是否有return语句)
- async函数内部return语句返回的值会成为then方法回调函数的参数(resolve/reject)。
- async函数返回的Promise对象必须等待内部所有await命令后面的Promise对象执行完才会发生状态改变,除非遇到return语句或者抛出错误。即async函数内部的异步操作执行完后才会执行then方法的回调函数
④ await命令
- 正常情况下,await命令后面是一个Promise对象,返回该对象的结果(返回promise对象执行的返回值),如果不是Promise对象就直接返回对应的值。
- 任何一个await语句后面的Promise对象变为reject状态,那么整个async函数会中断执行。
- ① 如果想要一个异步操作失败不影响后面的异步操作,可将出错的异步操作放置
try{}..catch(){}
中,这样不管该异步操作失败/成功都不会影响后续代码的执行 ② 另一个方法是在await后面的Promise对象后加一个catch方法,处理前面可能出现的错误。如果catch中有异步操作会先执行后续代码,最后再执行catch中的异步操作。
function sleep(interval) {
return new Promise(resolve => {
setTimeout(resolve, interval);
})
}
// 用法
async function one2FiveInAsync() {
for(let i = 1; i <= 5; i++) {
console.log(i);
await sleep(1000);//当该方法执行完后才会i++
}
return "hello";
}
console.log(one2FiveInAsync());
//出错处理方法
//①
async function f() {
try {
await Promise.reject('出错了');//将该Promise对象错误捕捉,不会影响后续操作
} catch(e) {
}
return await Promise.resolve('hello world');
}
f().then(v => console.log(v))// hello world
//②
async function f() {
await Promise.reject('出错了').catch(e => console.log(e));//捕获错误并输出
return await Promise.resolve('hello world');
}
f().then(v => console.log(v))
// 出错了
// hello world
⑤ 错误处理
- 如果await后面的异步操作出错,那么等同于async函数返回的Promise被reject。故可通过then方法的回调函数接受到await后面异步操作的错误信息。
- 为了避免由于一个await后面的异步操作导致后续代码无法执行,可将其放在
try{}catch{}
代码块中。
⑥ async函数使用注意点
- 最好将await命令放在
try...catch
代码块中- 如果有多个await命令,且其后面的异步操作不存在继发关系,最好让它们同时触发。
let foo = await getFoo();
let bar = await getBar();//该例子中,等到上一条语句执行完后才会执行这条语句。这样比较耗时。
//两种解决方案
//1
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
//2
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
- await命令只能用在async函数中,如果用在普通函数会报错
- async函数可以保留运行堆栈
//下面代码中,a的内部一个异步任务b(),当b()运行时,函数a不会终端执行,再b()执行完毕后,a可能早已经执行完毕。此时b函数所在的上下文环境消失。如果b()或c()报错,错误堆栈将不包括a()
const a = () => {
b().then(() => c());
};
//改进
//当b执行的时候,a会暂停执行。上下文环境保存着。当b()/c()报错时,错误堆栈将包括a()
const a = async ()=>{
await b();
c();
}