灏天阁

async 函数优雅的处理错误

· Yin灏

如果 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:出错了

上面代码中,async 函数 f 执行后,await 后面的 Promise 对象会抛出一个错误对象,导致 catch 方法的回调函数被调用,它的参数就是抛出的错误对象。

任何一个 await 语句后面的 Promise 对象变为 reject 状态,那么整个 async 函数都会中断执行。

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

上面代码中,第二个 await 语句是不会执行的,因为第一个 await 语句状态变成了 reject。

有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个 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

如果有多个 await 命令,可以统一放在 try…catch 结构中。

如果不想使用 try…catch 结构,你可以通过错误优先的方式方式统一处理结果。

async function f() {
  await fetch("/api/list")
    .then((data) => [null, data])
    .catch((err) => [err, undefined]);
}

async function main() {
  const [err, data] = await f();
  if (!err) {
    return await Promise.resolve("hello world");
  }
}

数组之中有两个元素,如果索引为 0 的元素不为空值,说明该请求报错,如果索引 0 的元素为空值说明该请求没有报错,也就是成功。

- Book Lists -