尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
用 async/await 重写 Promise 错误处理:以 GitHub 用户查询重试为例
文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载导读本文基于《现代 JavaScript 教程》中 async/await 章节的经典练习题完整讲解如何把一段基于.then/catch的「再次抛出rethrow」错误处理代码改写成async/await风格并重点演示如何借助while循环 try..catch摆脱原有的递归写法。读完本文你将掌握async/await与try..catch协同处理异步错误的标准模式学会用instanceof区分自定义错误类型、对未知错误进行再次抛出rethrow并理解递归式 promise 链改写成循环的具体思路。原题背景一段依赖.then/catch与递归的 rethrow 示例在 04-promise-error-handling 章节 中已经介绍过「再次抛出Rethrowing」的概念链尾端的.catch行为类似try..catch我们可以分析 error如果无法处理就将其再次抛出控制权随即移交至下一个最近的 error 处理程序。练习题给出的原始版本如下见 task.mdclass HttpError extends Error { constructor(response) { super(${response.status} for ${response.url}); this.name HttpError; this.response response; } } function loadJson(url) { return fetch(url) .then(response { if (response.status 200) { return response.json(); } else { throw new HttpError(response); } }); } // 询问用户名直到 github 返回一个合法的用户 function demoGithubUser() { let name prompt(Enter a name?, iliakan); return loadJson(https://api.github.com/users/${name}) .then(user { alert(Full name: ${user.name}.); return user; }) .catch(err { if (err instanceof HttpError err.response.status 404) { alert(No such user, please reenter.); return demoGithubUser(); // 递归调用自身继续询问 } else { throw err; // 未知 error再次抛出 } }); } demoGithubUser();这段代码有两个值得注意的痛点错误处理被迫依赖.catchcatch块中既要判断错误类型是否HttpError且状态码为 404又要在用户不存在时通过递归调用demoGithubUser()重新发起询问逻辑被then/catch的链式结构割裂递归代替循环为了「重新询问」代码选择了函数自调用而不是一个直观的循环。改造目标async/await 下的三条核心思路官方解答solution.md给出的核心思路非常简洁把demoGithubUser中的.catch替换为try...catch在需要等待 promise 的地方加上async/await在demoGithubUser中使用while(true)循环取代递归。第一步让 loadJson 变成 async 函数loadJson原本返回的是一个 promise 链改造后使用await直接取得fetch的结果并通过显式throw抛出非 200 状态对应的错误async function loadJson(url) { let response await fetch(url); if (response.status 200) { return response.json(); } else { throw new HttpError(response); } }这里的关键机制在 async/await 主章节 中有明确说明async关键字让函数总是返回一个 promise非 promise 的返回值会被自动包装进 resolved promise当 promise 被 reject 时await promise会像throw error一样抛出异常——这正是loadJson中throw new HttpError(response)能直接被外层try..catch捕获的原因当响应正常时return response.json()返回的仍是 promise会被async函数自动展开外层拿到解析后的 JSON 数据。第二步用 while 循环 try..catch 重写 demoGithubUser改造后的demoGithubUser完整代码如下与仓库解答一致// 询问用户名直到 github 返回一个合法的用户 async function demoGithubUser() { let user; while(true) { let name prompt(Enter a name?, iliakan); try { user await loadJson(https://api.github.com/users/${name}); break; // 没有 error退出循环 } catch(err) { if (err instanceof HttpError err.response.status 404) { // 循环将在 alert 后继续 alert(No such user, please reenter.); } else { // 未知的 error再次抛出rethrow throw err; } } } alert(Full name: ${user.name}.); return user; } demoGithubUser();对照原始版本可以看到三处结构性的改善await取代.thenuser await loadJson(...)直接拿到解析后的用户对象不再需要链式.then(user {...})try..catch取代.catch异常处理与业务代码位于同一作用域内逻辑顺序与「先请求、后判断」的直觉一致while(true)break取代递归try块执行成功没有错误就break退出循环遇到 404 错误时alert提示后自然进入下一轮循环完全消除了递归调用。深入原理catch 块里的两次分支判断改造后的catch(err)块浓缩了整个「再次抛出」模式值得逐行拆解if (err instanceof HttpError err.response.status 404) { alert(No such user, please reenter.); } else { throw err; }instanceof HttpError检查HttpError是自定义错误类继承自内建Error自定义错误的规范做法参见 2-custom-errors 章节。由于loadJson对非 200 响应统一抛出HttpError这里用instanceof可以精确识别「网络请求层面的业务错误」而不会误伤其他异常err.response.status 404二次判断HttpError构造函数把原始response对象挂到了this.response上构造时通过super(${response.status} for ${response.url})生成可读的message因此可以进一步区分「用户不存在404」与「其他 HTTP 错误」throw err再次抛出对无法处理的未知错误如网络中断、服务器 5xx 等catch块不做处理而是原样抛出。此时demoGithubUser()返回的 promise 会变为 rejected 状态调用方如最外层的demoGithubUser();之后追加的.catch或全局unhandledrejection事件浏览器环境可以接手处理避免错误被静默吞掉。值得注意的是HttpError携带response属性的设计与 自定义 Error 章节 中「自定义错误应支持message、name、stack并可以带有自己的专属属性」的指导完全一致属于「用自定义错误类辅助错误分析」的典型实践。两种写法的对比与适用场景维度.then/catch原始版async/await改造版错误处理语法.catch(err {...})try..catch块重新询问的实现递归调用demoGithubUser()while(true)循环 break控制流可读性链式回调顺序需脑内拼接同步风格书写自上而下错误类型分支同一catch内用if/else判断同一catch内用if/else判断两种版本在错误分析逻辑上是等价的都遵循「处理可处理的错误、rethrow 未知错误」的 promise 错误处理原则但async/await版本去掉了递归消除了潜在的调用栈深度增长问题代码也更贴近同步代码的阅读习惯。不过需要注意 async/await 主章节的提示async/await基于 promise在最外层作用域所有 async 函数之外无法使用await此时仍需用.then/catch收尾当需要并行等待多个 promise 时应组合使用await Promise.all([...])错误同样会通过try..catch捕获。扩展实践把这个模式迁移到其他场景「循环 try..catch instanceof rethrow」的组合并不只适用于 GitHub 用户查询。任何「需要反复重试的外部请求」都可以套用同一框架async function fetchWithRetry(url) { while (true) { try { let response await fetch(url); if (!response.ok) { throw new HttpError(response); } return await response.json(); } catch (err) { if (err instanceof HttpError err.response.status 404) { // 针对性的提示或等待然后继续循环 } else { throw err; // 未知错误交给上层处理 } } } }改造时只需记住两条规则需要等待 promise 的地方加await函数声明处加async把原来的.catch逻辑整体搬进try..catch把递归出口替换成break或return。这与练习题姊妹篇 01-rewrite-async 的思路一脉相承——那里演示了把loadJson的.then逐一替换为await的基础改造本文则进一步覆盖了循环与错误分支的重构。小结通过这道练习题可以提炼出三条可复用的实战经验await让「拿结果」和「抛错误」都变成同步语法promise reject 时await自动抛出异常配合try..catch即可用最朴素的方式处理异步错误循环是比递归更自然的「重试」表达在 async 函数里while(true)try..catchbreak完全取代了.catch内递归调用自身的写法自定义错误类 instanceof rethrow 构成健壮的错误边界只处理自己能处理的错误如 404 重试其余错误一律向上抛出交由外层或全局unhandledrejection处理这是生产级异步代码的基本素养。相关代码均可在仓库的 练习题 task.md 与 官方解答 solution.md 中直接运行验证配套的 async/await 主章节、promise 错误处理章节 与 自定义 Error 章节 提供了更完整的理论背景。赞分享文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载相关推荐Node.js 错误处理最佳实践用 Async/Await 与 Promise 重构异步错误处理Node.js 错误处理最佳实践用 Async/Await 与 Promise 重构异步错误处理 异步代码的错误处理是 Node.js 应用稳定性的分水岭。本文档教程后端Modern JavaScript Tutorial 实战用 async/await 重写 Promise 链式 rethrow 错误处理递归改循环Modern JavaScript Tutorial 实战用 async/await 重写 Promise 链式 rethrow 错误处理递归改循环文档/教程前端用 async/await 重写rethrow示例从 Promise 链到 try..catch 循环用 async/await 重写rethrow示例从 Promise 链到 try..catch 循环 导读 async/await 是 JavaScri文档/教程前端上一篇CANN/asc-devkit: asc_mul_add_relu函数下一篇从需求到代码MetaGPT企业级软件公司自动化全流程解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

React Native FlashList 测试指南:用 Jest 模拟布局测量,为高性能列表编写单元测试

React Native FlashList 测试指南:用 Jest 模拟布局测量,为高性能列表编写单元测试

移动开发UI组件跨平台 【免费下载链接】flash-list A better list for React Native 项目地址: https://gitcode.com/gh_mirrors/fl/flash-list 点击查看 免费下载 FlashList 是 React Native 平台上 FlatList 的高性能替代方案,其核心渲染机制建立在&q…

📅 2026/10/8 1:29:11
Learn X in Y minutes 法文版 HTML 指南精讲:从零掌握 HTML5 标记语言核心语法

Learn X in Y minutes 法文版 HTML 指南精讲:从零掌握 HTML5 标记语言核心语法

文档教程 【免费下载链接】learnxinyminutes-docs Code documentation written as code! How novel and totally my idea! 项目地址: https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs 点击查看 免费下载 本篇指南以 learnxinyminutes-docs 仓库中的 fr/h…

📅 2026/10/8 1:29:11
Hudi 复合记录键与大写字段名 COW 表构建与验证指南:Trino 连接器记录级索引剪枝实战

Hudi 复合记录键与大写字段名 COW 表构建与验证指南:Trino 连接器记录级索引剪枝实战

数据湖湖仓一体大数据数据存储 【免费下载链接】hudi Upserts, Deletes And Incremental Processing on Big Data. 项目地址: https://gitcode.com/gh_mirrors/hud/hudi 点击查看 免费下载 导读 本文以 hudi-trino 测试数据集中的生成脚本为核心,讲解如…

📅 2026/10/8 1:29:11
MORE NEWS

更多资讯

📰

iOS工程实战清单:开发者模式、链接唤起与后台音频排坑指南

iOS 第九章终于更新了。注意,这里的“iOS 第九章”不是 iOS 9 系统,也不是某个新框架的版本号,而是很多人一直在跟的 iOS 开发进阶系列里的最新一章。这章之所以比前面几章更难产,并不是因为它要讲什么新潮模型或者复杂的底层原理…

📰

iOS开发全流程:从环境搭建、真机调试到上架准备

兄弟们,iOS 系列的第九章终于更新了。这一章等得确实有点久,后台也一直有读者在催更。如果说前八章我们更多是在单个知识点上打转,那第九章的核心目标就很明确了:把之前零散的能力串成一条完整的 iOS 应用开发主线——从环境准备、…

📰

Windows 上通过 Cygwin 编译运行 Varnish 缓存实战指南

简介:Cygwin Varnish Cache 是一套面向 Windows 平台开发者与运维人员的开源修补方案,旨在解决 Varnish Cache 这款高性能 HTTP 缓存服务器无法直接在 Cygwin 模拟环境中运行的问题。项目通过对源码进行适配改造,覆盖文件路径处理、网络 I/O、…

📰

MinIO分片上传与断点续传:Java大文件上传实战避坑指南

简介:这是一份面向 Java 后端开发者的 MinIO 分片上传与断点续传实战示例,针对大文件直传易超时、网络中断需重传等痛点,给出可直接运行的完整方案。压缩包共 13 个文件,约 19KB,包含 7 个 Java 源码、2 个 JavaScript…

📰

eSIM-Tools通知系统开发指南:用Netlify Functions构建轻量级Toast通知的最佳实践

eSIM-Tools通知系统开发指南:用Netlify Functions构建轻量级Toast通知的最佳实践 【免费下载链接】eSIM-Tools 专为已有 Giffgaff 和 Simyo 号码的用户设计的现代化 eSIM 管理工具集,支持将物理 SIM 卡转换为 eSIM、设备更换和二维码生成。(A modern set…

📰

群晖NAS部署Dify:从零构建可维护的本地大模型平台

简介:本资源是专为群晖NAS用户设计的Dify开源AI应用部署安装包,面向希望在本地私有化环境中快速搭建大模型应用服务的开发者与技术爱好者,解决Synology平台缺乏官方Dify支持、手动部署门槛高的实际问题。压缩包共2000个文件,主体为…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬