异步请求 - async/await

130 阅读3分钟

async

1. 概念

  • 用于声明异步函数,返回值为一个Promise对象。
  • 类似以同步的方式来写异步方法。
  • 语法:
async function fn() {
    console.log('Hello World!');
}

console.log(fn.constructor); // Promise()
// 这里证明其返回值是一个Promise对象

2. 返回值

问题:返回值是一个Promise对象,那么函数本身定义的返回值去哪里了?
答:

  1. Promise的异步结果时通过.then()或者.catch()方法来获取并处理的。
  2. 如果异步函数回调resolve,则用then()处理;异步回调reject,则用.catch()处理。
// 使用.then()的情况
async function fn1() {
    return 'Hello world!';
}

fn1.then(res => {
    console.log(res); // Hello world!
})
// 使用.catch()的情况
async function fn2() {
    consolelog(a1); // a1未定义,则报错 => 回调reject方法
}

fn2.catch(err => {
    console.log(err); // ReferenceError: a1 is not defined
});
// 既有返回值,又有错误处理的时候
async function fn3() {
  console.log(a1);
  return 'Hello world!';
}

fn3().then(res => {
  console.log(res);
}).catch(error => {
  console.log(error); // ReferenceError: a1 is not defined
})

// 【注意】只会执行reject状态下的语句

await

1. 概念 - 等待

  • 语法:
var value = await myPromise();
  • 所谓等待,指暂停当前async function内部语句的执行,等待使用await声明的语句执行完成并返回结果后,继续执行async funciton函数内部的剩余语句
  • myPromise()是一个Promise对象,而自定义的变量value则用于获取Promise对象返回的resolve状态值。

2. 用法

  • await必须在async function使用,则会提示语法错误。
  • 如果await后面跟其他值,则直接返回该值。
async function fn() {
    console.log(1);
    var result = await new Promise(function(resolve, reject) {
        setTimeout(function(){
            resolve(2);
        }, 2000);
    });
    console.log(result);
    console.log(3);
    console.log(await 4); // 4 会被直接返回
}
fn();
// 1
// 2 (2 秒后输出)
// 3
// 4

3. 返回结果

  • await 会等到后面的Promise 返回结果 后才会执行async函数后面剩下的语句。
  • 也就是说,如果Promise 不返回结果(没有resolve/reject),后面的代码就不会执行。
async function fn() {
    console.log(1);
    await new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log(2);
        }, 2000);
    });
    console.log(3);
}
fn();
// 1
// 2 (2 秒后输出,并且后面不会继续输出 3)
  • 如果await 后面的 Promise 返回一个 reject 状态的结果,则会被当成 错误 抛出。
async function fn() {
    console.log(1);
    var result = await new Promise(function(resolve, reject) {
        setTimeout(function() {
            reject(2);
        }, 2000);
    });
    console.log(3);
}
fn();
// 1
// Uncaught (in promise) 2 (2 秒后输出)
// 3没有输出,说明异常抛出后,后面的执行也被忽略

4. 非await部分

  • 内部遇到await会等到返回结果再继续执行下去。
  • await部分仍然会以正常的异步/同步方式执行。(如遇到setTimeout()还是会放入任务队列中......)
async function fn() {
    console.log(0);
    
    await new Promise(resolve => {
        setTimeout(() => {
            console.log(1);
            resolve();
        }, 1000);
    });

    setTimeout(() => {
        console.log(2);
    }, 0);

    console.log(3);
}

fn();
// 0
// 1(2 秒后)
// 3
// 2

5. await内部

  • 函数会等待await返回结果再继续执行,但await内部的代码依然按正常的同步/异步执行。
async function fn() {
    console.log(0);
    
    setTimeout(() => {
        console.log(1);
    }, 0);

    await new Promise(resolve => {
        setTimeout(() => {
            console.log(2);
        }, 0);

        console.log(3);

        setTimeout(() => {
            console.log(4);
            resolve();
        }, 1000);

        setTimeout(() => {
            console.log(5);
        }, 0);
    });

    setTimeout(() => {
        console.log(6);
    }, 0);
    console.log(7);
}

fn();
// 0
// 3
// 1
// 2
// 5
// 4(2 秒后)
// 7
// 6

参考: knightyun.github.io/2019/08/02/…