前端异步系列(三)-async/await

120 阅读2分钟

1. 什么是async/await

异步函数,也称为“async/await”( Promise 语法关键字),是 ES6 期约模式在 JS 函数中的应用。 async/await 是 ES8 规范新增的。这个特性从行为和语法上都增强了 JavaScript,让以同步方式写的代码能够异步执行

以下是自己对 async/await 的基本概念理解与总结,不喜勿喷:

  1. async/await 本质上是一个语法糖,它是基于 Promise 的简化和封装
  2. await 可以理解成是 Promise 的 then 方法,只有执行 resolve 才会执行 then 方法
  3. 捕获 reject 建议使用 try/catch 来捕获 reject
  4. async 函数默认返回 Promsie 对象(被 Promise.resolve() 包装成期约对象),如果没有 return,则返回 undefined 的 Promise 对象

2. await

return返回值默认被包装成promsie对象,所以可以调用then方法

async function foo() {
  return 3                            // 会被包裹成Promise对象
}
foo().then(res => {console.log(res)}) // 输出3
async function bar() { 
  return await Promise.resolve('bar'); // await解析成'bar'字符串,经过async函数的return,'bar'又包裹成一个Promise对象
} 
bar().then(console.log);               // 所以这里才能执行then方法

3. 停止和恢复执行

  1. await 会等待后面的值封装成 Promise 对象在执行,即使 await 'bar' 是字符串也会把 'bar' 封装成 Promise 对象
  2. foo、bar、baz类似中文中的张三、李四
async function foo() { 
  console.log(await Promise.resolve('foo')); // 第二输出
} 
async function bar() { 
  console.log(await 'bar'); // 第三输出
  console.log('111')        // 最四输出
} 
async function baz() { 
  console.log('baz'); // 第一输出
} 
foo();
bar();
baz();

4. try/catch 捕获错误

  1. async/await 不能直接捕获 Promise 抛出的错误;async/await 需结合 try/catch 来捕获 Promise 的错误, 如果不需要捕获错误则可以不使用 try/catch
  2. 以下3种分别区分使用 async/await 和不使用 async/await 处理捕获错误的不同方式

定义个公共Promise函数

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = Math.random() > 0.5
      if (success) {
        resolve('Data fetched successfully')
      } else {
        reject('Failed to fetch data')
      }
    }, 1000)
  })
}
  1. 使用 try/catch + async/await 来捕获错误
try {
  const result = await fetchData();
  console.log(result);
} catch (error) {
  // 这里的catch可以直接捕获reject返回的内容
  console.error('Error:', error);
}
  1. 不使用 async/await ,直接使用 Promise 链式调用来捕获错误
fetchData()
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    // 这里的catch捕获reject返回的内容
    console.error('Error inside Promise chain:', error.message);
  });
  1. 如下方式一的 catch 并不会捕获到错误,因为没有通过异步模式捕获错误(PS: 也可以理解为 try/catch 无法直接捕获 Promise 的错误,必须要配合 async/await 才可以捕获错误)
// 方式一
try {
  new Promise((resolve, reject) => {
    reject('fail1')
  })
} catch(err) {
  console.log('错误内容1: ', err)  // 无法捕获 reject 错误
}

// 方式二
try {
  await new Promise((resolve, reject) => {
    reject('fail2')
  })
} catch(err) {
  console.log('错误内容: ', err)  // 可以捕获 reject 错误
}
  1. try/catch 无法捕获直接由 setTimeout 异步执行的错误;try/catch 只能捕获同步代码中的错误
try {
  setTimeout(() => {
    throw new Error('Async error')
  }, 1000);
} catch (error) {
  console.error('错误:', error.message);
}