async和await知识点总结

191 阅读3分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。

async和await是ES8新增的关键字。async用来声明一个函数是异步的。

async异步函数的写法

async异步函数可以有很多种写法。

async function foo1() {

}

const foo2 = async () => {

}

class Foo {
  async bar() {
    
  }
}

异步函数的执行流程

在异步函数中没有特殊代码的话,它跟普通函数的执行流程是一样的,默认会被同步执行。

async function foo() {
  console.log('开始执行');
  console.log('代码1');
  console.log('代码2');
  console.log('代码3');
  console.log('结束执行');
}

console.log('1111');
foo()
console.log('2222');

image.png

异步函数和普通函数的区别

区别一:异步函数的返回值一定是个Promise

异步函数的返回值一定是个Promise,调用异步函数后,我们可以使用then方法,catch方法。

async function foo() {
  console.log('开始执行');
  console.log('中间代码');
  console.log('执行结束');
}

const promise = foo()
promise.then(res => {
})

如果异步函数有返回值,那它会包裹到Promise的resolve中,此时res的值为异步函数返回的aaa。

async function foo() {
  console.log('开始执行');
  console.log('中间代码');
  console.log('执行结束');
  return 'aaa'
}

const promise = foo()
promise.then(res => {
  console.log('then方法执行', res);
})

如果异步函数的返回值是Promise,那么它会决定Promise.resolve的状态。

async function foo() {
  console.log('开始执行');
  console.log('中间代码');
  console.log('执行结束');
  
  return new Promise((resolve, reject) => {
    resolve('aaa')
  })
}

const promise = foo()
promise.then(res => {
  console.log('then方法执行', res);
})

如果异步函数的返回值是个对象并且实现了thenable,那么会由对象的then方法决定。

async function foo() {
  console.log('开始执行');
  console.log('中间代码');
  console.log('执行结束');
  
  return {
    then: function(resolve, reject) {
      resolve('aaa')
    }
  }
}

const promise = foo()
promise.then(res => {
  console.log('then方法执行', res);
})

区别二:抛出异常

在普通函数中,我们抛出异常,调用函数的后续代码不执行。

function foo() {
  console.log('代码开始执行');
  console.log('中间代码');
  throw new Error('错误信息')
  console.log('执行结束');
}

foo()
console.log('后续代码');

执行该代码,我们可以看到foo()后面的代码没有执行。

那么如果是在异步函数中抛出异常会如何呢?

异步函数中抛出的异常,会作为异步函数返回的Promise的reject值的,而且后续代码会执行。

async function foo() {
  console.log('代码开始执行');
  console.log('中间代码');
  throw new Error('错误信息')
  console.log('执行结束');
}

foo().catch(err => {
  console.log('err:', err);
})

console.log('后续代码');

区别3:异步函数中可以使用await关键字

如果在普通函数中使用await关键字,会报SyntaxError: await is only valid in async function的错误。

function foo() {
  await 123
}

foo()

在异步函数中可以使用await,await后面通常跟表达式,表达式的返回值是个Promise。

await后面跟表达式

function requestData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(111)
    }, 2000)
  })
}

async function foo() {
  const res1 = await requestData()
  console.log('后面代码1', res1);
  console.log('后面代码2');
  console.log('后面代码3');
}

foo()

await后面的代码相当于requestData()生成的Promise对象中的then方法里面的代码,是等到await执行有结果后才开始执行。

await后面除了跟表达式,还可以跟普通值,thenable对象以及新的Promise。

await后面跟普通值

如果await后面是一个普通的值,那么会直接返回这个值。

async function foo() {
  const res = await 123
  console.log(res);
}
foo()

await后面跟thenable对象

如果await后面是一个thenable对象,那么会根据对象的then方法调用来决定后续的值。

async function foo() {
  const res = await {
    then: function(resolve, reject) {
      resolve(123)
    }
  }
  console.log(res);
}
foo()

await后面跟新的Promise对象

如果await后面跟一个新的Promise对象,那么会根据这个新的Promise对象的状态来决定后续的值。

async function foo() {
  const res = await new Promise((resolve, reject) => {
    resolve(123)
  })
  console.log(res);
}
foo()

要注意的是,如果await后面的表达式,是返回的Promise的reject的状态,那么会将这个reject结果直接作为函数Promise的reject值。

function requestData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(111)
    }, 2000)
  })
}

async function foo() {
  const res = await requestData()
  console.log('res', res);
}

foo().catch(err => {
  console.log('err', err);
})