文章目录

  • async、await
  • 异步函数写法
  • 异步函数返回值
  • 异步函数的异常
  • await关键字
  • await处理异步请求


async、await

异步函数写法

async关键字用于声明一个异步函数:

  • async是asynchronous单词的缩写,异步、非同步
  • sync是synchronous单词的缩写,同步、同时

async异步函数和普通函数一样可以有很多中写法:

// 1.最常用的方式
async function foo1() {}
// 2.表达式定义异步函数
const foo2 = async function() {}
// 3.箭头函数定义异步函数
const foo3 = async () => {}
// 4.类中定义异步函数
class Person {
  async foo() {}
}

异步函数返回值

异步函数的内部代码执行过程和普通的函数是一致的,默认情况下也是会被同步执行。

异步函数有返回值时,和普通函数会有区别(异步函数返回的是一个Promise):

  • 情况一:异步函数有普通的返回值时,异步函数的返回值相当于被包裹到Promise.resolve中
async function foo() {
  return 321 // 相当于Promise.resolve(321)
}

foo().then(res => {
  console.log(res) // 321
})
  • 情况二:如果我们的异步函数的返回值是Promise,状态由会由Promise决定
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(["aaa", "bbb", "ccc"])
  }, 3000)
})

async function foo() {
  return promise
}

foo().then(res => {
  console.log(res) // 延迟三秒打印['aaa', 'bbb', 'ccc']
})
  • 情况三:如果我们的异步函数的返回值是一个对象并且实现了thenable,那么会由对象的then方法来决定
async function foo() {
  return {
    then: function(resolve, reject) {
      setTimeout(() => {
      resolve("aaa")
      }, 3000)
    }
  }
}

foo().then(res => {
  console.log(res) // 延迟三秒打印 aaa
})

异步函数的异常

什么情况下, 异步函数是已拒绝 (rejected) 状态

  • 异步函数返回一个Promise主动调用reject会变成rejected状态
async function foo() {
  return new Promise((resolve, reject) => {
    reject("err rejected")
  })
}

foo().then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err) // err: err rejected
})
  • 如果我们在async中抛出了异常,那么程序它并不会像普通函数一样报错,而是会作为Promise的reject来传递;
async function foo() {
  // 抛出一个异常
  throw new Error("my async funtion error")
  return "aaa"
}

foo().then(res => {
  console.log("res:", res)
}).catch(err => {
  // catch会捕获异常
  console.log("err:", err) // err: Error: my async funtion error
})

await关键字

async函数另外一个特殊之处就是可以在它内部使用await关键字,而普通函数中是不可以的。

await关键字有什么特点呢?

  • 通常使用await是后面会跟上一个表达式,这个表达式会返回一个Promise
  • 那么await会等到Promise的状态变成fulfilled状态,之后继续执行异步函数
  • await后面表达的结果如果是fulfilled状态, 那么await会将Promise的resolve结果返回
function bar() {
  console.log("bar函数")
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(123)
    }, 3000)
  })
}

async function foo() {
  console.log("await关键字前面的代码")

  // await后续跟一个表达式, 表达式返回一个Promise时, 会等待Promise有结果后, 将resolve的结果返回, 继续执行后续代码
  const res = await bar()
  console.log(res)

  console.log("await关键字后面的代码")
}

foo()

// 打印结果
// 1. 直接打印
// await关键字前面的代码

// bar函数
// 2. 等待三秒再打印
// 123
// await关键字后面的代码

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

async function foo() {
  console.log("await关键字前面的代码")

  const res = await 123
  console.log(res)

  console.log("await关键字后面的代码")
}

foo()

// 打印结果
// await关键字前面的代码
// 123
// await关键字后面的代码

如果await后面的表达式,返回的Promiseed是reject的状态,那么相当于在异步函数中抛出了一个异常, 我们可以在catch方法中捕获, rejected状态后面的异步函数代码不会执行

function bar() {
  console.log("bar函数")
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject("err message")
    }, 3000)
  })
}

async function foo() {
  console.log("await关键字前面的代码")

  const res = await bar()
  console.log(res)

  console.log("await关键字后面的代码")
}

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

// 打印结果
// 1.直接打印
// await关键字前面的代码
// bar函数

// 2.等待三秒打印
// err err message

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

function bar() {
  console.log("bar函数")
  return {
    then: function(resolve, reject) {
      resolve("aaa")
    }
  }
}

async function foo() {
  console.log("await关键字前面的代码")

  const res = await bar()
  console.log(res)

  console.log("await关键字后面的代码")
}

foo()

// 打印结果
// await关键字前面的代码
// bar函数
// aaa
// await关键字后面的代码

await处理异步请求

上一篇中, 我们最终是使用生成器处理网络请求, 在学习了await后, 我们可以使用await处理异步请求, 再进一步的优化代码

  • 为了方便大家观看, 我将上一篇中的代码拿过来可以回顾一下
// 封装模拟网络请求的函数
function requestData(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(url)
    }, 2000)
  })
}

// 生成器的处理方案
function* getData() {
  const res1 = yield requestData("why")
  console.log("res1:", res1)

  const res2 = yield requestData(res1 + "kobe")
  console.log("res2:", res2)

  const res3 = yield requestData(res2 + "james")
  console.log("res3:", res3)
}

// 自动化执行生成器函数(了解)
function execGenFn(genFn) {
  // 1.获取对应函数的generator
  const generator = genFn()
  // 2.定义一个递归函数
  function exec(res) {
    const result = generator.next(res)
    if (result.done) return
    result.value.then(res => {
      exec(res)
    })
  }
  // 3.执行递归函数
  exec()
}
  • 我们再使用async函数和await关键字重构上面代码
function requestData(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(url)
    }, 2000);
  })
}

async function getData() {
  const res1 = await requestData("aaa")
  console.log("res1:", res1) // aaa

  const res2 = await requestData(res1 + "bbb")
  console.log("res2:", res2) // aaabbb
  
  const res3 = await requestData(res2 + "ccc")
  console.log("res3:", res3) // aaabbbccc
}

// catch用于捕获异常
getData().catch(err => {
  console.log("err:", err)
})