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

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));

 

相关文章:

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

1、Promise.all 的错误处理 Promise.all 方法接受一个 Promise 数组,并返回所有解析 Promise 的结果数组: const promise1 Promise.resolve("one"); const promise2 Promise.resolve("two");Promise.all([promise1, promise2]).…...

腾讯云:数智教育专场-学习笔记

15点13分2024年10月21日(短短5天的时间,自己的成长速度更加惊人)-开始进行“降本增效”学习模式,根据小米手环对于自己的行为模式分析(不断地寻找数据之间的关联性),每天高效记忆时间&#xff0…...

Ovis: 多模态大语言模型的结构化嵌入对齐

论文题目:Ovis: Structural Embedding Alignment for Multimodal Large Language Model 论文地址:https://arxiv.org/pdf/2405.20797 github地址:https://github.com/AIDC-AI/Ovis/?tabreadme-ov-file 今天,我将分享一项重要的研…...

python的Django的render_to_string函数和render函数模板的使用

一、render_to_string render_to_string 是 Django 框架中的一个便捷函数,用于将模板渲染为字符串。 render_to_string(template_name.html, context, requestNone, usingNone) template_name.html:要渲染的模板文件的名称。context:传递给…...

基于Python大数据的王者荣耀战队数据分析及可视化系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...

【Linux学习】(3)Linux的基本指令操作

前言 配置Xshell登录远程服务器Linux的基本指令——man、cp、mv、alias&which、cat&more&less、head&tail、date、cal、find、grep、zip&tar、bc、unameLinux常用热键 一、配置Xshell登录远程服务器 以前我们登录使用指令: ssh 用户名你的公网…...

Mac 使用脚本批量导入 Apple 歌曲

最近呢,买了一个 iPad,虽然家里笔记本台式都有,显示器都是 2个,比较方便看代码(边打游戏边追剧)。 但是在床上拿笔记本始终还是不方便,手机在家看还是小了点,自从有 iPad 之后&…...

全桥PFC电路及MATLAB仿真

一、PFC电路原理概述 PFC全称“Power Factor Correction”(功率因数校正),PFC电路即能对功率因数进行校正,或者说是能提高功率因数的电路。是开关电源中很常见的电路。功率因数是用来描述电力系统中有功功率(实际使用…...

【安当产品应用案例100集】025-确保数据安全传输——基于KMS与HSM的定期分发加密解决方案

引言: 在当今快速发展的数字化时代,企业面临着前所未有的信息安全挑战。尤其是在需要向供应商定期分发敏感数据的情况下,如何保证这些数据在传输过程中的安全性变得至关重要。为此,我们推出了结合安当KMS密钥管理平台与HSM密码机…...

十 缺陷检测解决策略之三:频域+空域

十 缺陷检测解决策略之三:频域空域 read_image (Image, 矩形) * 中间低频,四周高频 fft_image (Image, ImageFFT) * 中间低频,四周高频 fft_generic (Image, ImageFFT1, to_freq, -1, sqrt, dc_center, complex) * 中间高频,四周低频 rft_ge…...

有望第一次走出慢牛

A股已走完30多年历程。 大约每十年,会经历一轮牛熊周期。特点是每一轮周期,大约九成的时间都是熊市主导。就是我们常说的 快牛慢熊。 这一次,会不会重复历史? 历史不会简单重复。已经感受到了盘面的变化。 有人说,股市爆涨爆…...

计算机网络(十二) —— 高级IO

#1024程序员节 | 征文# 目录 一,预备 1.1 重新理解IO 1.2 五种IO模型 1.3 非阻塞IO 二,select 2.1 关于select 2.2 select接口参数解释 2.3 timeval结构体和fd_set类型 2.4 socket就绪条件 2.5 select基本工作流程 2.6 简单select的服务器代…...

电力行业 | 等保测评(网络安全等级保护)工作全解

电力行业为什么要做网络安全等级保护? 电力行业是关系到国家安全和社会稳定的基础性行业,电力行业信息化程度相对较高,是首批国家信息安全等级保护的重点行业。 01 国家法律法规的要求 1994《计算机信息系统安全保护条例》(国务…...

总裁主题CeoMax-Pro主题7.6开心版

激活方式: 1.授权接口源码ceotheme-auth-api.zip搭建一个站点,绑定www.ceotheme.com域名,并配置任意一个域名的 SSL 证书。 2.在 hosts 中添加:127.0.0.1 www.ceotheme.com 3.上传class-wp-http.php到wp-includes目录&#xff…...

深入探讨编程的核心概念、学习路径、实际应用以及对未来的影响

在当今这个数字化时代,编程已成为连接现实与虚拟世界的桥梁,它不仅塑造了我们的生活方式,还推动了科技的飞速发展。从简单的网页制作到复杂的人工智能系统,编程无处不在,其重要性不言而喻。本文旨在深入探讨编程的核心…...

IDEA如何将一个分支的代码合并到另一个分支(当前分支)

前言 我们在使用IDEA开发Java应用时,经常是和git一起使用的。我们对于git常用的操作包括提交,推送,拉取代码等。还有一个重要的功能是合并代码。 那么,我们应该如何合并代码呢? 如何合并代码 首先,我们…...

Python实现基于WebSocket的stomp协议调试助手工具

stomp协议很简单,但是搜遍网络竟没找到一款合适的客户端工具。大多数提供的都是客户端库的使用。可能是太简单了吧!可是即便这样,假如有一可视化的工具,将方便的对stomp协议进行抓包调试。网上类似MQTT的客户端工具有很多&#xf…...

基于neo4j的旅游知识图谱维护与问答系统

你还在为毕业设计发愁吗?试试这个基于Neo4j的旅游知识图谱维护与问答系统吧!这套系统不仅功能强大,而且几乎涵盖了你需要的一切,完美助力你的毕业项目! 系统介绍 该系统是专门针对旅游景点信息的知识图谱工具&#x…...

竞赛学习路线推荐(编程基础)

关于学习路线的推荐,总体上,分两步学习,第一步学习编程语言(C、C、java),第二步是学习数据结构和算法 不少初学者会选择C语言或C作为首选,笔者这里也推荐C或C作为入门,需要注意的是&…...

webRTC搭建:STUN 和 TURN 服务器 链接google的有点慢,是不是可以自己搭建

如果使用 Google 提供的 STUN/TURN 服务器速度较慢,你完全可以自己搭建 STUN 和 TURN 服务器。这有助于提升网络连接速度和稳定性,特别是在需要穿透 NAT 或防火墙的网络环境下。 下面是如何自己搭建 STUN 和 TURN 服务器的具体步骤: 1. 选择…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

【HTTP三个基础问题】

面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...

如何在网页里填写 PDF 表格?

有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据&#xff…...

MySQL账号权限管理指南:安全创建账户与精细授权技巧

在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则&#xf…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 ​…...

uniapp 字符包含的相关方法

在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...