参考了阮老师的ES6教程案例,加上自己的整理,总结了async...await常见用法:

async用于申明function异步,await用于等待一个异步方法执行完成

先介绍async的用法:

1、async函数返回一个 Promise 对象 

//一个普通函数
function getData(){
    return "syy";
}
console.log(getData())  //syy

//加上async后
async function getData(){
    return "syy";
}
console.log(getData());  //Promise {<resolved>: "syy"}

2、async函数内部return语句返回的值,会成为then方法回调函数的参数 

async function getData(){
    return "syy";
}
getData().then(data=>{
    console.log(data)  //syy
});

3、async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态,抛出的错误对象会被catch方法回调函数接收到

async function getData(){
    throw new Error('出错了');
}
getData()
.then(v=>{
    console.log(v)
})
.catch(e=>{
    console.log(e)  //Error: 出错了
});
async function getData() {
    throw new Error('出错了');
}
getData()
.then(
    v => console.log(v),
    e => console.log(e)   //Error: 出错了
)

4、async 函数有多种使用形式

1⃣️ async function foo() {} 

2⃣️ const foo = async function () {}

     const foo = async () => {}

3⃣️ let obj = { async foo() { } }

     obj.foo().then(...)

开始进入async...await主题:

1、正常情况下,await命令后面是一个Promise对象。如果不是,会被转成一个立即resolve的Promise对象。

async function getData(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            var name = "syy";
            resolve(name)
        },1000)
    })
}
async function test(){
    var p = await getData();
    console.log(p);
};
test(); //syy
async function f() {
  return await 123;
}
f()
.then(v => 
    console.log(v)
)  //123

2、await命令后面的 Promise 对象如果变为reject状态,则reject的参数会被catch方法的回调函数接收到

//上面代码中,await语句前面没有return,但是reject方法的参数依然传入了catch方法的回调函数。这里如果在await前面加上return,效果是一样的。
async function f() {
  await Promise.reject('出错了');
}
f()
.then(v => 
    console.log(v)
)
.catch(e => 
    console.log(e)
)  //出错了

3、Promise 对象的状态变化:async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。

只要一个await语句后面的 Promise 变为reject,那么整个async函数都会中断执行

async function f() {
    await Promise.reject('出错了');
    await Promise.resolve('hello world');   //不会执行
}   //Promise {<rejected>: "出错了"}

4、前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个await放在try...catch结构里面,这样不管这个异步操作是否成功,第二个await都会执行

async function f() {
  try {
      await Promise.reject('出错了');
  } catch(e) {
  }
  return await Promise.resolve('hello world');
}
f()
.then(v => 
    console.log(v)
)  //hello world


//另一种方法:await后面的 Promise 对象再跟一个catch方法,处理前面可能出现的错误
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

5、错误处理:如果await后面的异步操作出错,那么等同于async函数返回的 Promise 对象被reject

async function f() {
    await new Promise(function (resolve, reject) {
        throw new Error('出错了');
    });
}
f()
.then(v => 
    console.log(v)
)
.catch(e => 
    console.log(e)
)  //Error:出错了

6、多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发

let foo = await getFoo();
let bar = await getBar();
//上面代码中,getFoo和getBar是两个独立的异步操作(即互不依赖),被写成继发关系。这样比较耗时,因为只有getFoo完成以后,才会执行getBar,完全可以让它们同时触发
写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
//上面两种写法,getFoo和getBar都是同时触发,这样就会缩短程序的执行时间