现代 JavaScript 教程实战:用 async/await 重写 loadJson 的 Promise 链(附完整解法与源码解析)

发布时间:2026/10/8 1:42:24

现代 JavaScript 教程实战:用 async/await 重写 loadJson 的 Promise 链(附完整解法与源码解析) 文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载本篇基于《现代 JavaScript 教程》中文仓库中 1-js/11-async/08-async-await/01-rewrite-async/task.md 的经典练习题展开把一个基于.then/.catch的loadJson(url)网络请求封装改写为async/await语法。读完本文你将掌握async函数返回值的规则、await的暂停与取值语义、throw与 promise rejection 的等价关系以及在非async顶层作用域中如何配合.catch消费异步结果 —— 这也是从 Promise 链平滑过渡到async/await的关键一步。一、练习背景源自 Promise 链一章的 loadJson 示例本题要求重写的代码出自教程的 Promise 链Promise chaining 一章。那一章用fetch封装了一个读取 JSON 的工具函数基本形态如下function loadJson(url) { return fetch(url) .then(response response.json()); }而练习题给出的完整版本在此基础上加入了状态码校验function loadJson(url) { return fetch(url) .then(response { if (response.status 200) { return response.json(); } else { throw new Error(response.status); } }); } loadJson(https://javascript.info/no-such-user.json) .catch(alert); // Error: 404这段代码的两个关键行为状态码分流fetch在服务器返回响应头时即 resolve并非等完整响应下载完response.status 200表示成功此时调用response.json()返回一个解析 JSON 的新 promise否则直接throw new Error(response.status)该异常会被 promise 机制捕获使返回的 promise 变为 rejected。错误透传调用方在顶层通过.catch(alert)捕获 rejection最终弹出Error: 404。任务要求不改变功能仅把.then链重写为async/await形式。二、参考解法async 函数 await 的逐步改写练习题的标准答案位于 01-rewrite-async/solution.md完整代码如下async function loadJson(url) { // (1) let response await fetch(url); // (2) if (response.status 200) { let json await response.json(); // (3) return json; } throw new Error(response.status); } loadJson(https://javascript.info/no-such-user.json) .catch(alert); // Error: 404 (4)改写要点逐条解析给函数加上async关键字注释 (1)。这是使用await的前提也保证函数无论内部逻辑如何返回值都会被包装成一个 promise。关于这一点教程正文 08-async-await/article.md 明确指出async确保函数总是返回一个 promise其他值会被自动包装进一个 resolved 的 promise。用await替换.then注释 (2)。await fetch(url)让 JavaScript 引擎挂起当前函数的执行直到fetch返回的 promise settle若成功表达式的值就是 resolve 的结果即response对象并直接赋值给let response。教程强调这种“暂停”不耗费 CPU引擎可以同时处理其他脚本与事件。对response.json()同样使用await注释 (3)拿到解析后的 JSON 对象作为函数返回值async函数会自动把该值包装成 resolved promise。错误处理交给外部的.catch注释 (4)。async函数内部throw new Error(response.status)会让loadJson(...)返回的 promise 变为 rejected与原来.then内部的throw行为完全等价因此loadJson(...).catch(alert)依旧弹出Error: 404。三、两个易混点能否直接return response.json()与内部 await解法注释特别提醒一个常见疑问能不能不await response.json()直接return response.json()答案是可以。因为async函数会自动把返回值即使是一个 promise展开并包装成最终 promise两种写法对外部调用者来说结果一致if (response.status 200) { return response.json(); // 不等待直接把 promise 返回 }区别在于直接return时函数在解析 JSON 完成之前就返回了此时必须由外部代码await这个 promise 才能真正拿到数据。在本例只做状态码校验中无关紧要因此标准解法选择了更直观的await写法让数据在函数内部就绪。作为良好实践在async函数内部应尽量await掉所有需要结果的 promise保证函数返回时数据已可用。第二个易混点是“非 async 顶层不能用 await”。解法注释 (4) 专门说明这里不能写await loadJson(...)因为调用语句位于所有async函数之外顶层await只有在现代浏览器的 module 作用域中才被允许。因此顶层的标准做法仍是.catch(alert)。这是async/await与promise.then/catch长期共存的根本原因教程在 08-async-await/article.md 的错误处理小节中也有同样的总结在语法上无法使用await的顶层通常需要追加.then/catch处理最终结果或错误。四、从示例看 await 的错误传播机制本题中throw new Error(response.status)之所以能被外层的.catch(alert)捕获底层依据是await与throw的等价关系。教程正文给出了这一对等价写法async function f() { await Promise.reject(new Error(Whoops!)); } // 等价于 async function f() { throw new Error(Whoops!); }即如果被await的 promise 被 rejectawait会像执行了throw一样抛出该错误。在真实场景中reject 可能延迟发生此时await抛出错误之前会有相应延时但传播机制不变。若希望就地处理错误可以使用常规的try..catch包装多行awaitasync function f() { try { let response await fetch(/no-user-here); let user await response.json(); } catch(err) { // 同时捕获 fetch 与 response.json() 的错误 alert(err); } }五、仓库同章进阶练习rethrow 循环中的 try..catch同目录下还有一道进阶练习 02-rewrite-async-2/task.md它把本题思想延伸到“请求 GitHub 用户信息直到输入合法为止”的重试场景原实现用.catch内递归调用demoGithubUser()实现重试。改用async/await后递归可以被while(true)循环取代class HttpError extends Error { constructor(response) { super(${response.status} for ${response.url}); this.name HttpError; this.response response; } } async function loadJson(url) { let response await fetch(url); if (response.status 200) { return response.json(); } else { throw new HttpError(response); } } 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(No such user, please reenter.); // 循环继续 } else { throw err; // 未知错误重新抛出 } } } alert(Full name: ${user.name}.); return user; } demoGithubUser();这段代码展示了async/await相对 Promise 链的一个显著优势try..catch能把异步错误当作同步异常处理配合while循环实现“重试直到成功”的流程代码是扁平的顺序结构而非回调嵌套或链式递归。完整解法见 02-rewrite-async-2/solution.md。六、延伸一题在普通函数中调用 async 函数同章的 03-async-from-regular/task.md 与本题互补考察“普通函数内如何拿到 async 函数的结果”。由于await不能出现在非async函数中正确做法是把async调用当作普通 promise用.then消费结果async function wait() { await new Promise(resolve setTimeout(resolve, 1000)); return 10; } function f() { // 1 秒后显示 10 wait().then(result alert(result)); } f();这也再次印证了本文的核心认知async/await不是对 promise 的替代而是建立在 promise 之上的语法糖。任何async函数调用都返回 promise因此在await不可用的作用域.then/.catch依然是标准接口。相关源码级示例可对照 03-promise-chaining 章节 中fetch链式调用与loadJson拆分的完整代码。七、小结本题沉淀的四个要点async声明函数必定返回 promise并允许函数体内使用awaitawait暂停函数直到 promise settle成功时返回结果失败时抛出错误等价于throwasync函数内可return response.json()直接返回 promise但通常应await后再返回保证函数返回时数据已就绪顶层非async作用域无法使用await必须用.then/.catch消费结果或捕获错误现代浏览器 module 顶层除外。本练习完整代码与标准答案位于仓库 1-js/11-async/08-async-await/01-rewrite-async/ 目录含 task.md 与 solution.md可作为独立代码片段直接在浏览器控制台运行验证。赞分享文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载相关推荐JavaScript.info 实战用 async/await 重写 Promise 链式 loadJson 请求JavaScript.info 实战用 async/await 重写 Promise 链式 loadJson 请求 本篇技术指南以 Modern JavaSc文档/教程前端JavaScript Promise 链改写为 async/await 实战以 loadJson 网络请求为例JavaScript Promise 链改写为 async/await 实战以 loadJson 网络请求为例 导读 本文将围绕《Modern JavaScr文档/教程前端Modern JavaScript Tutorial 实战用 async/await 重写 Promise 链式 rethrow 错误处理递归改循环Modern JavaScript Tutorial 实战用 async/await 重写 Promise 链式 rethrow 错误处理递归改循环文档/教程前端上一篇FFXVIFix开源工具动态帧率控制与超宽屏适配解决方案 | 最终幻想16玩家的画质增强指南下一篇License_Plate_Detection_Pytorch部署指南从Pytorch模型到生产环境的全流程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/8 1:37:24

电子保险丝+MCU:构建可管理可恢复的电源路径保护方案

1. 电源路径保护为什么是嵌入式设计的隐形门槛1.1 “保险丝够用就行”的代价我实验室的废板堆里躺着一块让人心疼的控制板:输入是24V开关电源,后端是DC-DC,前级只装了一颗自恢复保险丝。听起来很常规,直到现场反馈“上电就冒烟”。…

2026/10/8 4:02:37

AI大模型如何清洗地质勘探语料?从OCR乱码到规范标注的完整方案

简介:这份PDF方案由AI产品社编写,面向地质勘探研究人员、工程师及技术管理人员,系统讲解AI大模型在地质语料清洗与标注中的应用路径。内容从项目背景与目标切入,覆盖数据源选择、网络爬虫/数据库检索/现场调查等收集方法&#xff…

2026/10/8 4:02:37

基于TPS259483AYWPR与PIC18F4525的嵌入式电源路径保护方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 4:02:37

qiankun微前端容器标准化改造:基座瘦身与子应用接入契约实践

接手一个已经跑了一年多的 qiankun 微前端项目,第一件让我头疼的事不是某个子应用挂了,而是基座(主应用)越来越像一个“业务应用”,而不是一个“容器”。路由表堆了两百多条,导航菜单在基座里写死&#xff…

2026/10/8 4:02:37

Vue动态组件+keep-alive:从页面卡顿到秒切的全流程优化

做后台管理系统久了,你会对“页面切换”这四个字特别敏感。用户点一下菜单,页面从列表切到详情,再切回来,如果滚动条归零、表单填了一半被清空、列表重新 loading,那就是一次不合格的体验——这类问题,我这…

2026/10/8 4:02:37

RTX PRO 6000跑DeepSeek V4 Flash实测:Blackwell单卡推理全栈指南

1. 项目概述:一张专业卡跑大模型推理,到底行不行? 最近有好几拨朋友在群里甩链接问:“RTX PRO 6000真能跑DeepSeek V4 Flash吗?”“ExLlamaV3在Blackwell架构上是不是又翻车了?”——问题背后不是单纯的好…

2026/10/8 3:57:37

OPNET仿真QoS配置实战:WFQ队列与ToS标记详解

简介:面向OPNET 14.5用户的计算机网络仿真作业10资源包,聚焦服务质量(QoS)仿真实验,适合学习《计算机网络仿真OPNET实用指南》的读者及需要完成类似课程作业的高校学生。资源覆盖FIFO、RED、WRED、WFQ、WFQ-LLQ等多种队…

2026/10/5 6:32:56

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/7 8:18:33

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/6 17:46:51

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 0:02:17

自然数立方等于连续奇数之和:从证明到编程验证

十几年来我一直游走在数学科普和编程教学这两块内容之间,对“看起来像魔法、拆开全是数学”的结论总是格外敏感。最近翻资料时又撞见一句话:任何一个自然数 m 的立方,都可以写成 m 个连续奇数之和。2 的立方等于 3 加 5,3 的立方等…

2026/10/8 0:02:17

C#上位机SSH连接实战:用SSH.NET补齐超时、批量与密钥认证

简介:这是一份基于 C# 开发的 SSH 连接功能半成品工程,原本作为另一个主项目的子功能模块,现独立打包分享。工程采用 WinForms 界面,包含源码、解决方案、安装部署工程、NuGet 依赖包及说明文档,适合正在做远程连接、网…

2026/10/8 0:02:17

Java SpringBoot一体化智能售后系统设计与实现全解析

毕业设计年年做,Java Web 方向的题目翻来覆去就那么几个,但“一体化智能售后系统”这个题,每次看到我都觉得值得认真聊一聊。它不是一个简单 curd 堆出来的管理系统,而是把客户、工单、派单、处理、回访、统计整条链路串起来的一套…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑