1. Promise.then 的基本用法与工作机制
Promise.then 的基本语义
then 是 Promise 的实例方法,用于在 Promise 解决(resolve)或拒绝(reject)后执行对应的回调。它接收两个可选参数:onFulfilled 和 onRejected,分别处理成功和失败的分支。
执行时,回调 不会立即执行,而是在当前任务队列的微任务阶段进入队列,待 Promise 状态确定后按顺序执行。返回值是一个新的 Promise,允许进行链式操作。
需要特别注意的是,如果 onFulfilled 或 onRejected 中抛出异常,返回的 Promise 将被拒绝,并传递该异常。
// 基本用法
fetch('/api/data').then(response => response.json()) // 成功回调.then(data => console.log(data)) // 继续链式调用.catch(err => console.error(err)); // 错误处理链式调用与返回值的影响
在 then 的回调中返回的值会被下一个 then 捕获;如果返回的是一个 Promise,下一步会等待该 Promise 的状态变更,从而实现异步顺序控制。
链式调用 的核心特性是连续使用 then,形成流水线式的异步处理。

下面的示例展示返回数值 vs 返回 Promise 的影响:
// 返回数值,后续 then 接收该值
Promise.resolve(1).then(v => v + 1).then(v => console.log(v)); // 2// 返回 Promise,后续 then 等待该 Promise
Promise.resolve(1).then(v => Promise.resolve(v + 1)).then(v => console.log(v)); // 2常见错误场景与解决策略
在使用 then 时,常见错误包括:忘记返回一个 Promise、在回调中直接抛出异常、以及错误没有向上抛至链头的 catch。
解决策略包括:始终返回 一个 Promise 或值,避免直接抛错,并在链的末端显式使用 catch 或第三方错误处理方案。
错误示例与正确用法对比:
// 错误示例:不返回 Promise
fetch('/api').then(data => { data.json(); }) // 未返回值// 正确示例:返回 Promise
fetch('/api').then(data => data.json()).then(json => console.log(json));2. Promise.then 的实战技巧与常见组合
错误处理策略:catch 与 第一个完成的处理
在实际场景中,全局错误处理 常用做法是在链的末端添加 catch,以捕获所有未处理的错误。也可以在链的某些阶段为 onRejected 提供单独的处理函数。
catch 只捕获来自上游链路的错误;如果在 catch 内重新抛错,链条会继续向上传递该错误。
全局错误处理的典型用法:
// 全局错误捕获
fetch('/api').then(res => res.json()).then(data => process(data)).catch(err => console.error('请求失败:', err));与 Promise.all、Promise.race 的协作
在并发场景中,Promise.all 可以将多个 Promise 聚合成一个,便于在 then 中统一处理结果。若任意一个 Promise 失败,整个组会进入 reject 路径。
如果使用 Promise.race,则谁先完成就触发对应的 then,这是实现超时、优先选择的常用技巧。
示例:
// Promise.all 示例
const requests = [fetch('/a'), fetch('/b'), fetch('/c')];
Promise.all(requests).then(results => Promise.all(results.map(r => r.json()))).then(allJson => console.log(allJson)).catch(err => console.error('其中一个请求失败:', err));// Promise.race 示例
const p1 = new Promise(resolve => setTimeout(() => resolve('slow'), 3000));
const p2 = new Promise(resolve => setTimeout(() => resolve('fast'), 1000));
Promise.race([p1, p2]).then(v => console.log(v));异步流程中的顺序控制与微任务队列
在事件循环模型中,Promise.then 的回调进入微任务队列,保证在同一轮事件循环中尽快执行。但如果大量微任务堆积,也可能导致界面卡顿。
理解 同步边界 与 异步边界,可以帮助设计更平滑的 UI 流程,避免在渲染阶段重复触发微任务。
微任务队列的执行顺序示例:
// 微任务示例:顺序执行
console.log('start');
Promise.resolve().then(() => console.log('microtask 1'));
Promise.resolve().then(() => console.log('microtask 2'));
console.log('end'); // 先输出 start, end, microtask 1, microtask 23. 实战示例:从 API 调用到页面渲染
获取多资源并按顺序渲染
本节演示如何通过 Promise.then 链结合 fetch 获取多资源,并按顺序将数据渲染到页面。通过串联 then,可以把每一步的结果传递下去。
通过将数据处理和 DOM 更新分离成独立阶段,可读性与可维护性 得到提升。记得在末端保持清晰的错误处理。
// 获取多资源并按顺序渲染
fetch('/api/first').then(res => res.json()).then(first => {document.getElementById('first').textContent = first.name;return fetch('/api/second');}).then(res => res.json()).then(second => {document.getElementById('second').textContent = second.title;}).catch(err => console.error('渲染失败:', err));异常兜底与回退数据
在网络波动或接口不可用时,提供一个 兜底数据 可以提升用户体验。可以在 catch 处设定回退方案。
通过在失败时切换到回退数据,仍然保持页面的可用性与连贯性。
// 异常兜底示例
fetch('/api/data').then(res => res.ok ? res.json() : Promise.reject('请求错误')).then(data => {render(data);}).catch(err => {renderFallback();console.warn('使用回退数据:', err);}); 

