Frontend Academy · 课时

Promise:then、catch、finally 与 Promise.all

创建并链式调用 Promise,在 catch 代码块中处理错误,在 finally 中执行清理,并使用 Promise.all 并行运行多个 Promise。

第 3 / 4 课13 个步骤

Promise:then、catch、finally 与 Promise.all 是 CoddyKit 上的免费 Frontend Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Frontend Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Frontend Academy 课程共包含 4 节课。

什么是 Promise?

Promise 表示一个将在未来可用的值。它是一个处于以下三种状态之一的对象:等待中(初始状态)、已兑现(resolve 并得到一个值)或已拒绝(因某个原因失败)。Promise 一旦确定状态,该状态就不会改变。

创建 Promise

请使用 new Promise(executor) 构造函数创建 Promise。executor 函数会接收 resolve 和 reject 回调。成功时请使用成功值调用 resolve,失败时请使用错误调用 reject。

const delay = (ms) => new Promise((resolve) => {
  setTimeout(resolve, ms);
});

const fetchData = (url) => new Promise((resolve, reject) => {
  fetch(url)
    .then(res => res.json())
    .then(resolve)
    .catch(reject);
});

.then()——处理成功结果

promise.then(onFulfilled) 会注册一个回调,在 Promise 成功完成时运行。它会接收已解析的值。.then() 会返回一个新的 Promise,因此可以进行链式调用。

fetch('/api/users')
  .then(response => response.json())
  .then(users => {
    console.log('Users:', users);
    return users.length;
  })
  .then(count => console.log('Count:', count));

.catch()——处理错误

promise.catch(onRejected) 用于处理拒绝。将它放在链的末尾,可以捕获上方任意步骤产生的错误。

fetch('/api/data')
  .then(res => {
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return res.json();
  })
  .then(data => processData(data))
  .catch(err => {
    console.error('Failed:', err.message);
    showErrorToUser();
  });

.finally()——始终运行

promise.finally(onFinally) 无论 Promise 成功完成还是被拒绝,都会运行。它非常适合执行清理工作,例如隐藏加载指示器、释放锁和记录分析数据。

showSpinner();
fetch('/api/data')
  .then(res => res.json())
  .then(render)
  .catch(handleError)
  .finally(() => hideSpinner()); // always runs

Promise 链——返回值

从 .then() 返回一个值,该值就会成为下一个 .then() 接收到的已解析值。返回一个新的 Promise,即可按顺序链接异步操作。

getUser(id)
  .then(user => getOrders(user.id))  // return Promise
  .then(orders => orders[0])          // return value
  .then(order => console.log(order)); // receive order

Promise.all()——并行运行

Promise.all([p1, p2, p3]) 会等待所有 Promise 完成,并按相同顺序返回结果数组。如果任何一个 Promise 被拒绝,整个操作会立即被拒绝。

const [user, posts, comments] = await Promise.all([
  fetch('/api/user/1').then(r => r.json()),
  fetch('/api/posts').then(r => r.json()),
  fetch('/api/comments').then(r => r.json()),
]);
// All three run in parallel — much faster than sequential

Promise.allSettled()——不快速失败

Promise.allSettled() 会等待所有 Promise 确定状态(完成或拒绝),并返回一个结果对象数组,其中每个对象都会包含状态和值,或包含状态和原因。当您不希望一个失败导致所有结果都无法使用时,它非常有用。

const results = await Promise.allSettled([p1, p2, p3]);
results.forEach(result => {
  if (result.status === 'fulfilled') use(result.value);
  else logError(result.reason);
});

Promise.race() 与 Promise.any()

Promise.race() 会以最先确定状态的 Promise 的结果完成或拒绝。Promise.any() 会以第一个成功完成的 Promise 的结果完成(忽略拒绝,只有在全部拒绝时才会被拒绝)。它们适用于超时处理和冗余请求。

// Timeout pattern:
const withTimeout = (promise, ms) => Promise.race([
  promise,
  new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), ms))
]);

创建已确定状态的 Promise

Promise.resolve(value) 会创建一个已经以 value 完成的 Promise。Promise.reject(error) 会创建一个已经被拒绝的 Promise。它们适用于测试和适配器函数。

const p = Promise.resolve(42);
p.then(v => console.log(v)); // 42

未处理的拒绝事件

如果 Promise 被拒绝时没有 .catch() 处理,就会变成未处理的拒绝。现代浏览器和 Node.js 会发出警告。请始终附加 .catch(),或在使用 async/await 时使用 try/catch。

window.addEventListener('unhandledrejection', event => {
  console.error('Unhandled rejection:', event.reason);
  event.preventDefault();
});

快速检查

哪个静态方法可以并行运行多个 Promise,并以包含所有结果的数组完成?

回顾:Promise

使用 .then() 处理成功结果,使用 .catch() 处理错误,使用 .finally() 执行清理。链会传递值。Promise.all() 可实现并行处理。Promise.allSettled() 可以容忍部分失败。Promise.race() 用于获取最快结果。请始终处理拒绝。现代代码使用 async/await 作为 Promise 之上的语法糖。

免费开始

用 AI 导师学习 HTML — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
41
课程
163

常见问题解答

「Promise:then、catch、finally 与 Promise.all」课时是免费的吗?

是的 — 「Promise:then、catch、finally 与 Promise.all」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Frontend Academy 课程的其余内容,请升级到 CoddyKit PRO。 Frontend Academy 课程共包含 4 节课。

「Promise:then、catch、finally 与 Promise.all」这节课中我会学到什么?

创建并链式调用 Promise,在 catch 代码块中处理错误,在 finally 中执行清理,并使用 Promise.all 并行运行多个 Promise。 你通过在浏览器中直接运行的动手代码来练习 Frontend Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Frontend Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Frontend Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「Promise:then、catch、finally 与 Promise.all」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Frontend Academy 课中编写并运行代码吗?

能。每节 Frontend Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 事件循环:调用栈、队列与微任务
  2. 回调与回调地狱
  3. Promise:then、catch、finally 与 Promise.all
  4. async/await 与错误处理
← 返回 Frontend Academy