当前位置: 首页 > article >正文

Promise、async、await 、异步生成器的错误处理方案

1、Promise.all 的错误处理

Promise.all 方法接受一个 Promise 数组,并返回所有解析 Promise 的结果数组:

const promise1 = Promise.resolve("one");
const promise2 = Promise.resolve("two");

Promise.all([promise1, promise2]).then((results) => console.log(results));

// 结果: ['one', 'two']

如果这些 Promise 中的任何一个被拒绝,Promise.all 将拒绝并返回第一个被拒绝的 Promise 的错误。

为了在 Promise.all 中处理这些情况,可以使用 catch:

const promise1 = Promise.resolve("good");
const promise2 = Promise.reject(Error("Bad"));
const promise3 = Promise.reject(Error("Bad+"));

Promise.all([promise1, promise2, promise3])
  .then(results => console.log(results))
  .catch(error => console.error(error.message));

如果想要运行一个函数而不考虑 Promise.all 的结果,可以使用 finally:

Promise.all([promise1, promise2, promise3])
  .then(results => console.log(results))
  .catch(error => console.error(error.message))
  .finally(() => console.log("Finally"));

2、Promise.any 的错误处理

Promise.any 和 Promise.all 恰恰相反。Promise.all 如果某一个失败,就会抛出第一个失败的错误。而 Promise.any 总是返回第一个成功的 Promise,无论是否发生任何拒绝。

相反,如果传递给 Promise.any 的所有 Promise 都被拒绝,那产生的错误就是 AggregateError。 来看下面的例子:

const promise1 = Promise.reject(Error("Error"));
const promise2 = Promise.reject(Error("Error+"));

Promise.any([promise1, promise2])
  .then(result => console.log(result))
  .catch(error => console.error(error))
  .finally(() => console.log("Finally"));

输出结果如下:

fileOf7174.png

这里用 catch 处理错误。AggregateError 对象具有与基本错误相同的属性,外加一个 errors 属性:

const promise1 = Promise.reject(Error("Error"));
const promise2 = Promise.reject(Error("Error+"));

Promise.any([promise1, promise2])
  .then(result => console.log(result))
  .catch(error => console.error(error.errors))
  .finally(() => console.log("Finally"));

此属性是一个包含所有被拒绝的错误信息的数组:

fileOf7174.png

3、Promise.race 的错误处理

Promise.race 接受一个 Promise 数组,并返回第一个成功的 Promise 的结果:

const promise1 = Promise.resolve("one");
const promise2 = Promise.resolve("two");

Promise.race([promise1, promise2]).then(result => 
  console.log(result)
);

// 结果:one

那如果有被拒绝的 Promise,但它不是传入数组中的第一个呢:

const promise1 = Promise.resolve("one");
const rejection = Promise.reject(Error("Bad"));
const promise2 = Promise.resolve("two");

Promise.race([promise1, rejection, promise2]).then(result =>
  console.log(result)
);

// 结果:one

这样结果还是 one,不会影响正常的执行。

如果被拒绝的 Promise 是数组的第一个元素,则 Promise.race 拒绝,就必须要必须捕获拒绝:

const promise1 = Promise.resolve("one");
const rejection = Promise.reject(Error("Bad"));
const promise2 = Promise.resolve("two");

Promise.race([rejection, promise1, promise2])
  .then(result => console.log(result))
  .catch(error => console.error(error.message));

// Bad

4、Promise.allSettled 的错误处理

Promise.allSettled 是 ECMAScript 2020 新增的 API。它和 Promise.all 类似,不过不会被短路,也就是说当 Promise 全部处理完成后,可以拿到每个 Promise 的状态, 而不管其是否处理成功。

来看下面的例子:

const promise1 = Promise.resolve("Good!");
const promise2 = Promise.reject(Error("Bad!"));

Promise.allSettled([promise1, promise2])
  .then(results => console.log(results))
  .catch(error => console.error(error))
  .finally(() => console.log("Finally"));

这里向 Promise.allSettled 传递了一个包含两个 Promise 的数组:一个已解决,另一个已拒绝。

输出结果如下:

fileOf7174.png

5、async/await 的错误处理

JavaScript 中的 async/await 表示异步函数,用同步的方式去编写异步,可读性更好。

下面来改编上面的同步函数 toUppercase,通过将 async 放在 function 关键字之前将其转换为异步函数:

async function toUppercase(string) {
  if (typeof string !== "string") {
    throw TypeError("Expected string");
  }

  return string.toUpperCase();
}

只需在 function 前加上 async 前缀,就可以让函数返回一个 Promise。这意味着我们可以在函数调用之后链式调用 then、catch 和 finally:

toUppercase("hello")
  .then(result => console.log(result))
  .catch(error => console.error(error.message))
  .finally(() => console.log("Always runs!"));

当从 async 函数中抛出异常时,异常会成为底层 Promise 被拒绝的原因。任何错误都可以从外部用 catch 拦截。

除此之外,还可以使用 try/catch/finally 来处理错误,就像在同步函数中一样。

例如,从另一个函数 consumer 中调用 toUppercase,它方便地用 try/catch/finally 包装了函数调用:

async function toUppercase(string) {
  if (typeof string !== "string") {
    throw TypeError("Expected string");
  }

  return string.toUpperCase();
}

async function consumer() {
  try {
    await toUppercase(98);
  } catch (error) {
    console.error(error.message);
  } finally {
    console.log("Finally");
  }
}

consumer();

输出结果如下:

fileOf7174.png

6、异步生成器的错误处理

JavaScript 中的异步生成器是能够生成 Promise 而不是简单值的生成器函数。它将生成器函数与异步相结合,结果是一个生成器函数,其迭代器对象向消费者公开一个 Promise。

要创建一个异步生成器,需要声明一个带有星号 * 的生成器函数,前缀为 async:

async function* asyncGenerator() {
  yield 33;
  yield 99;
  throw Error("Bad!"); // Promise.reject
}

因为异步生成器是基于 Promise,所以同样适用 Promise 的错误处理规则,在异步生成器中,throw 会导致 Promise 拒绝,可以用 catch 拦截它。

要想从异步生成器处理 Promise,可以使用 then:

const go = asyncGenerator();

go.next().then(value => console.log(value));
go.next().then(value => console.log(value));
go.next().catch(reason => console.error(reason.message));

输出结果如下:

fileOf7174.png

也使用异步迭代 for await...of。 要使用异步迭代,需要用 async 函数包装 consumer:

async function* asyncGenerator() {
  yield 33;
  yield 99;
  throw Error("Bad"); // Promise.reject
}

async function consumer() {
  for await (const value of asyncGenerator()) {
    console.log(value);
  }
}

consumer();

与 async/await 一样,可以使用 try/catch 来处理任何异常:

async function* asyncGenerator() {
  yield 33;
  yield 99;
  throw Error("Bad"); // Promise.reject
}

async function consumer() {
  try {
    for await (const value of asyncGenerator()) {
      console.log(value);
    }
  } catch (error) {
    console.error(error.message);
  }
}

consumer();

输出结果如下:

fileOf7174.png

从异步生成器函数返回的迭代器对象也有一个  throw()  方法。在这里对迭代器对象调用 throw() 不会抛出异常,而是 Promise 拒绝:

async function* asyncGenerator() {
  yield 33;
  yield 99;
  yield 11;
}

const go = asyncGenerator();

go.next().then(value => console.log(value));
go.next().then(value => console.log(value));

go.throw(Error("Reject!"));

go.next().then(value => console.log(value)); 

输出结果如下:

fileOf7174.png

可以通过以下方式来捕获错误:

go.throw(Error("Let's reject!")).catch(reason =>
  console.error(reason.message)
);

我们知道,迭代器对象的 throw() 是在生成器内部发送异常的。所以还可以使用以下方式来处理错误:

async function* asyncGenerator() {
  try {
    yield 33;
    yield 99;
    yield 11;
  } catch (error) {
    console.error(error.message);
  }
}

const go = asyncGenerator();

go.next().then(value => console.log(value));
go.next().then(value => console.log(value));

go.throw(Error("Reject!"));

go.next().then(value => console.log(value));

 


http://www.kler.cn/news/367259.html

相关文章:

  • linux中的PATH环境变量
  • Jetpack架构组件_LiveData组件
  • Linux中级(DNS域名解析服务器)
  • 通过ssh端口反向通道建立并实现linux系统的xrdp以及web访问
  • python爬虫基础篇:http协议、请求头、响应头
  • 解决Redis缓存穿透(缓存空对象、布隆过滤器)
  • 挂耳式耳机品牌排行榜前十名有哪些?平价开放式耳机品牌推荐!
  • 【CSS3】css开篇基础(5)
  • 今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 10月27日,星期日
  • Vuejs设计与实现 — 同构渲染
  • R_机器学习——常用语法技巧汇总
  • 地球村上一些可能有助于赚钱的20个思维方式
  • php流程控制
  • 27.9 调用go-ansible执行playbook拷贝json文件重载采集器
  • 安全知识见闻-网络类型、协议、设备、安全
  • 落地台灯什么牌子好?口碑最好的落地灯品牌
  • vscode使用法则及神器介绍
  • Vue学习记录之二十三 Vue3环境变量的使用
  • 聊一聊检查代码中的输入输出错误类型有哪些
  • 大模型Transformer笔记:KV缓存
  • vscode配色主题与图标库推荐
  • 论文阅读(二十九):Multi-scale Interactive Network for Salient Object Detection
  • 一个关于@JsonIgnore的isxxx()问题
  • 接口测试(五)jmeter——get请求
  • Spring Ai 对接智谱清言结合vue(清测成功)
  • 面向对象高级-继承