【js篇】Promise 基本用法完全指南

38 阅读4分钟

Promise 是现代 JavaScript 异步编程的基石。它让复杂的异步操作变得可读、可维护、可组合

本文将系统讲解 Promise创建方式、核心方法(then/catch/all/race/finally) 和实际应用场景,助你彻底掌握这一关键技能。


一、创建 Promise 对象的三种方式

✅ 方式1:使用 new Promise()

最标准的方式,接收一个执行器函数(executor),该函数有两个参数:resolvereject

const myPromise = new Promise((resolve, reject) => {
  // 同步代码立即执行
  console.log('Promise 正在执行...');

  // 模拟异步操作
  setTimeout(() => {
    const success = Math.random() > 0.5;
    if (success) {
      resolve('✅ 操作成功!');
    } else {
      reject(new Error('❌ 操作失败!'));
    }
  }, 1000);
});
  • resolve(value):将状态变为 fulfilled,传递 value
  • reject(error):将状态变为 rejected,传递错误原因。

✅ 方式2:Promise.resolve(value)

快捷创建一个已成功Promise

// 等价于 new Promise(resolve => resolve(42))
const p1 = Promise.resolve(42);

p1.then(value => {
  console.log(value); // 42
});

使用场景:

  • 返回已知结果的 Promise;
  • 将非 Promise 值包装成 Promise(便于链式调用)。

✅ 方式3:Promise.reject(reason)

快捷创建一个已失败Promise

// 等价于 new Promise((resolve, reject) => reject(new Error('Oops')))
const p2 = Promise.reject(new Error('请求超时'));

p2.catch(err => {
  console.error(err.message); // 请求超时
});

二、实战示例:带条件的 Promise

function testPromise(ready) {
  return new Promise((resolve, reject) => {
    if (ready) {
      resolve("Hello World!");
    } else {
      reject("No thanks");
    }
  });
}

// 调用
testPromise(true)
  .then(
    msg => console.log(msg),        // 成功回调 → "Hello World!"
    error => console.log(error)     // 失败回调(可省略)
  );

testPromise(false).catch(err => {
  console.log(err); // "No thanks"
});

💡 .then() 接收两个可选参数:onFulfilledonRejected


三、Promise 的五大核心方法

1️⃣ .then():处理成功与失败

.then()Promise 最核心的方法,用于注册状态改变后的回调。

promise.then(
  value => { /* fulfilled 回调 */ },
  error => { /* rejected 回调 */ }
);

✅ 链式调用(串行异步任务)

// 串行请求:必须按顺序执行
ajax('first')
  .then(res1 => {
    console.log('第一请求完成:', res1);
    return ajax('second'); // 返回新 Promise
  })
  .then(res2 => {
    console.log('第二请求完成:', res2);
    return ajax('third');
  })
  .then(res3 => {
    console.log('第三请求完成:', res3);
  })
  .catch(err => {
    console.error('任一请求失败:', err);
  });

📌 关键点

  • .then() 返回新的 Promise,支持链式调用;
  • 返回值决定下一个 .then 的行为(普通值、Promise、抛错)。

2️⃣ .catch():统一错误处理

.catch() 专门处理 rejected 状态,相当于 .then(null, onRejected)

// 推荐写法:分离成功和失败处理
ajax('/api/data')
  .then(data => {
    console.log('数据:', data);
  })
  .catch(error => {
    console.error('请求失败:', error.message);
  });

🔥 强大功能:捕获链中任何错误

ajax('step1')
  .then(() => {
    throw new Error('中间出错');
  })
  .then(() => {
    console.log('不会执行');
  })
  .catch(err => {
    console.log('被捕获:', err.message); // 会执行
  });

✅ 最佳实践:总是使用 .catch()try/catch(async 函数中)来避免静默错误


3️⃣ .all():并行执行,全成功才通过

Promise.all(iterable) 接受一个 Promise 数组,所有都成功才 resolve,任一失败则 reject。

const p1 = new Promise(resolve => setTimeout(() => resolve(1), 2000));
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 1000));
const p3 = new Promise(resolve => setTimeout(() => resolve(3), 3000));

Promise.all([p1, p2, p3])
  .then(results => {
    console.log(results); // [1, 2, 3] —— 按数组顺序返回
  })
  .catch(err => {
    console.error('任一请求失败:', err);
  });

✅ 实际应用:并发请求

// 同时加载用户、文章、评论
Promise.all([
  fetch('/api/user'),
  fetch('/api/posts'),
  fetch('/api/comments')
]).then(([userRes, postsRes, commentsRes]) => {
  return Promise.all([
    userRes.json(),
    postsRes.json(),
    commentsRes.json()
  ]);
}).then(([user, posts, comments]) => {
  console.log({ user, posts, comments });
});

4️⃣ .race():竞速模式,谁快用谁

Promise.race(iterable) 返回第一个完成的 Promise 的结果。

const p1 = new Promise((_, reject) => setTimeout(() => reject(1), 2000));
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 1000));
const p3 = new Promise(resolve => setTimeout(() => resolve(3), 3000));

Promise.race([p1, p2, p3])
  .then(result => {
    console.log(result); // 2 —— p2 最快
  })
  .catch(err => {
    console.log('最快的是 reject:', err);
  });

✅ 实际应用:设置超时

function timeout(ms) {
  return new Promise((_, reject) => {
    setTimeout(() => reject(new Error('请求超时')), ms);
  });
}

Promise.race([
  fetch('/api/slow-data'),
  timeout(5000) // 5秒后超时
])
.then(response => response.json())
.catch(err => console.error('Error:', err.message)); // 可能是网络错误或超时

5️⃣ .finally():无论成败,都要执行

.finally() 指定最终一定会执行的操作,常用于清理资源。

let loading = true;

fetch('/api/data')
  .then(res => res.json())
  .then(data => {
    console.log(data);
  })
  .catch(err => {
    console.error(err);
  })
  .finally(() => {
    loading = false; // 关闭加载动画
    console.log('请求结束');
  });

🔍 重要特性

  • 不接收参数:无法知道前面是成功还是失败;
  • 不影响结果finally 中的返回值被忽略;
  • 等价于
promise.then(
  result => { /* 操作 */; return result; },
  error => { /* 操作 */; throw error; }
);

四、其他静态方法(ES2020+)

方法说明
Promise.allSettled()等待所有 Promise 结束,返回结果数组(包含 statusvalue/reason
Promise.any()第一个 fulfilled 的 Promise 决定结果;全部 reject 才 reject

✅ 示例:Promise.allSettled

const promises = [
  fetch('/api/user').catch(() => 'Failed'),
  fetch('/api/posts').catch(() => 'Failed')
];

Promise.allSettled(promises).then(results => {
  results.forEach((result, index) => {
    if (result.status === 'fulfilled') {
      console.log(`请求 ${index} 成功:`, result.value);
    } else {
      console.log(`请求 ${index} 失败:`, result.reason);
    }
  });
});

五、总结:Promise 方法对比表

方法用途成功条件失败条件
.then()链式处理异步上一个 resolve上一个 reject 或抛错
.catch()错误处理-捕获链中任一错误
.all()并行,全成功所有 fulfilled任一 rejected
.race()竞速第一个 fulfilled第一个 rejected
.allSettled()全部结束总是成功,返回结果数组不会 reject
.any()“或”逻辑第一个 fulfilled所有 rejected
.finally()清理操作传递原结果传递原错误

💡 结语

“掌握 Promise 的五种方法,就掌握了现代异步编程的钥匙。”

  • .then() 处理成功;
  • .catch() 统一错误;
  • .all() 并发执行;
  • .race() 设置超时;
  • .finally() 清理资源。

这些方法让你的异步代码更健壮、更高效、更易读