十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Axios 中的 Promise 机制深度解析:then/catch/finally、async/await 与并行请求的源码级实践

Axios 中的 Promise 机制深度解析:then/catch/finally、async/await 与并行请求的源码级实践 Axios 中的 Promise 机制深度解析then/catch/finally、async/await 与并行请求的源码级实践【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axiosAxios 构建于 ES6 原生 Promise API 之上每一次请求都返回一个标准的 Promise——成功时 resolve 为AxiosResponse响应对象失败时 reject 为AxiosError。本文以官方文档中的 Promise 指南为主体系统讲解then/catch/finally、async/await、Promise.all并行请求与请求链的完整用法并结合lib/core源码揭示一个请求究竟在什么时机被 resolve、在什么条件下被 reject的底层机制帮助读者从调用层面深入到实现层面真正掌握 Axios 的异步编程模型。Axios 基于原生 Promise API 构建Axios 的每个请求方法axios.get、axios.post、axios.request等返回的都是 JavaScript 标准的 Promise 对象其语义是resolve 为一个响应对象或 reject 为一个错误。这意味着你可以直接把它交给任何遵循 Promise/A 规范的库和语言特性来处理无需 Axios 特有的异步 API。适用前提如果你的运行环境不支持 ES6 原生 Promise例如某些旧版浏览器需要先引入一个 polyfill例如es6-promise再使用 Axios。对于现代 Node.js 与浏览器环境Promise 是内置能力无需额外处理。从源码结构看这一标准 Promise承诺贯穿整条请求链路lib/core/Axios.js 中Axios.prototype.request是一个async方法见 request 方法其内部_request通过Promise.resolve(config)起步再逐个.then()串联请求拦截器、dispatchRequest和响应拦截器见 Promise 链构建最终返回的正是这条链末端的 Promise各 HTTP 方法别名get/post/put/patch等都只是对this.request(...)的包装见 方法别名定义因此所有入口返回的 Promise 行为完全一致。TypeScript 中的AxiosPromiseT, D, P对于 TypeScript 集成类型定义中的AxiosPromiseT, D, P即PromiseAxiosResponseT, D, {}, P定义在 index.d.ts。三个泛型分别对应响应数据类型、请求体类型和查询参数类型请求侧数据会保留在response.config中declare const search: AxiosPromiseSearchResponse, RequestBody, SearchParams; search.then((response) { response.data; // SearchResponse response.config.data; // RequestBody | undefined response.config.params; // SearchParams | undefined });这个类型设计的好处是在then回调里不仅能拿到强类型的data还能回溯当次请求实际发出的 body 和 query 参数例如用于日志、重试或埋点而不必在闭包里额外保存一份副本。then / catch / finally由于 Axios 返回标准 Promise.then()、.catch()和.finally()可以按原生语义直接处理请求结果axios.get(/api/users) .then((response) { console.log(response.data); }) .catch((error) { console.error(Request failed:, error.message); }) .finally(() { console.log(Request finished); });结合源码可以更清楚地理解then与catch各自捕获的是什么then回调收到的response是完整的AxiosResponse包含data、status、headers、config、request而不只是data。浏览器端测试 promise.browser.test.js 中的 should provide succinct object to then 用例就验证了这一点await axios(/foo)之后response.data.hello、response.status、response.headers[content-type]与response.config.url均可访问。catch回调收到的错误由settle统一产生。lib/core/settle.js 根据config.validateStatus判定结果状态码通过校验默认 2xx则调用resolve(response)否则调用reject(new AxiosError(...))且当状态码落在 400–499 区间时错误码被标记为ERR_BAD_REQUEST否则为ERR_BAD_RESPONSE错误信息为Request failed with status code status。这也解释了为什么在catch中可以通过error.response拿到服务端响应体settle将config、request、response一并传入了AxiosError构造器。此外请求被取消AbortController或CancelToken时被拒绝的不是普通的 HTTP 状态错误而是CanceledError——dispatchRequest在执行前后都会检查取消状态见 throwIfCancellationRequested可用axios.isCancel(error)区分。async / await对大多数代码库官方推荐的写法是async/await它让异步代码读起来像同步代码也更容易组织错误处理async function fetchUser(id) { try { const response await axios.get(/api/users/${id}); return response.data; } catch (error) { console.error(Failed to fetch user:, error.message); throw error; } }几个与源码对应的实践要点await axios.get(...)解出的对象即AxiosResponse业务层通常需要的是response.data注意不要遗漏这一层上例中catch后重新throw error是常见模式在统一记录日志/上报的同时让调用方仍能感知失败避免静默吞错由于Axios.request本身是 async 函数lib/core/Axios.js它还会在捕获到错误后尝试为错误对象补全/合并stack因此在async/await场景下拿到的错误堆栈信息更利于排查问题。并行请求Promise.all 与 Promise.allSettled由于 Axios 返回标准 Promise可以直接用Promise.all同时发出多个请求并等待它们全部完成const [users, posts] await Promise.all([ axios.get(/api/users), axios.get(/api/posts), ]); console.log(users.data, posts.data);官方文档同时给出了一条重要提示Promise.all在任一请求失败时会立即整体 reject。如果需要容忍部分失败例如首屏聚合多个独立接口某个接口挂了不应拖垮整页应改用Promise.allSettledconst results await Promise.allSettled([ axios.get(/api/users), axios.get(/api/posts), ]); results.forEach((result) { if (result.status fulfilled) { console.log(result.value.data); } else { console.error(Request failed:, result.reason.message); } });两种策略的取舍可以概括为Promise.all适合数据有强依赖、缺一即失败的场景如订单详情必须包含商品与库存Promise.allSettled适合各数据块相互独立、可降级展示的场景。除了直接使用原生 APIAxios 还在入口层暴露了等价便捷方法lib/axios.js 中定义了axios.all (promises) Promise.all(promises)和axios.spread spread底层实现在 lib/helpers/spread.js。promise.browser.test.js 中的两个用例分别验证了axios.all([true, 123])的结果聚合以及axios.all([...]).then(axios.spread((a, b) ...))将数组参数摊开传给回调的能力——后者在两个请求的返回需要作为两个独立参数使用时比手动解构更简洁。链式请求用 then 串联依赖型调用当第二个请求依赖第一个请求的结果时可以用.then()链式调用把数据从一个请求传递到下一个axios.get(/api/user/1) .then(({ data: user }) axios.get(/api/posts?userId${user.id})) .then(({ data: posts }) { console.log(Posts for user:, posts); }) .catch(console.error);这段代码里有几个值得注意的细节.then回调中返回一个新的 Promise即新的 Axios 请求原链条会自动等待它完成后再把结果传给下一个.then——这是 Promise 链透明展平的机制无需嵌套回调解构{ data: user }直接取响应体保持链条简洁链末的单个.catch(console.error)可以捕获整条链上任意一环的失败第一段请求失败、第二段请求失败、甚至.then回调内抛出的同步异常都会汇聚到该catch。对照 dispatchRequest 的内部实现可以确认链中的每个请求节点都是完整的一次请求适配器返回的 Promise 在成功分支中执行transformResponse默认包含 JSON 解析并把headers规范化为AxiosHeaders实例在失败分支中若错误带有response也会对其data执行同样的转换后再Promise.reject(reason)见 onAdapterRejection。也就是说链式请求中每一环拿到的response.data都已经是解析后的 JSON且catch分支中的error.response.data如存在同样是被转换过的数据。小结统一语义所有请求入口都返回标准 Promiseresolve 为AxiosResponse、reject 为AxiosErrorHTTP 状态错误或CanceledError可直接与then/catch/finally、async/await及一切 Promise 组合原语配合使用失败判定点唯一且可定制是否 reject 由validateStatus决定实现集中在 settle.js4xx/5xx 分别对应ERR_BAD_REQUEST/ERR_BAD_RESPONSE组合能力完整Promise.all快速失败与Promise.allSettled容忍部分失败覆盖并行场景.then返回请求即可实现依赖型链式调用axios.all/axios.spread提供等价便捷方法类型友好AxiosPromiseT, D, P将请求体与查询参数保留在response.config中便于在强类型环境中做日志与重试。【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表