
文档教程前端【免费下载链接】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),仅供参考