> ## Content Index
> Fetch the complete content index at: https://blog.vercanti.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# JavaScript Promise 完全指南
- URL: https://blog.vercanti.com/javascript-promise-wan-quan-zhi-nan/
- Published: 2026-08-28T14:35:16.000Z
- Updated: 2026-08-28T14:58:26.000Z
- Description: 1. 什么是 Promise(JavaScript%20Promise%20完全指南.md#1-什么是-promise) 2. Promise 的三种状态(JavaScript%20Promise%20完全指南.md#2-promise-的三种状态) 3. 创建 Promise(JavaScript%20Promise%20完全指南.md#3-创建-promise) 4. 实例方法(JavaScript%20Promise%20完全指南.md#4-实例方法) - .then()(JavaScript%20Promise%20完全指南.md#41-t
- Author: yellowdog
- Tags: 前端开发

> 官方文档：<https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global%5FObjects/Promise>  
> 涵盖：每个方法、每个参数的含义、基础用法、进阶模式、最佳实践  
> 最后更新：2026-03-05（经官方文档复核）

---

## 目录

1. [什么是 Promise](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#1-%E4%BB%80%E4%B9%88%E6%98%AF-promise)
2. [Promise 的三种状态](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#2-promise-%E7%9A%84%E4%B8%89%E7%A7%8D%E7%8A%B6%E6%80%81)
3. [创建 Promise](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#3-%E5%88%9B%E5%BB%BA-promise)
4. [实例方法](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#4-%E5%AE%9E%E4%BE%8B%E6%96%B9%E6%B3%95)  
  - [.then()](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#41-then)
  - [.catch()](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#42-catch)
  - [.finally()](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#43-finally)
5. [静态方法](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#5-%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95)  
  - [Promise.resolve()](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#51-promiseresolve)
  - [Promise.reject()](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#52-promisereject)
  - [Promise.all()](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#53-promiseall)
  - [Promise.allSettled()](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#54-promiseallsettled)
  - [Promise.any()](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#55-promiseany)
  - [Promise.race()](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#56-promiserace)
  - [Promise.withResolvers()](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#57-promisewithresolvers)
  - [Promise.try()](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#58-promisetry)
6. [Promise 链式调用](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#6-promise-%E9%93%BE%E5%BC%8F%E8%B0%83%E7%94%A8)
7. [错误处理模式](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#7-%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86%E6%A8%A1%E5%BC%8F)
8. [async / await 与 Promise 的关系](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#8-async--await-%E4%B8%8E-promise-%E7%9A%84%E5%85%B3%E7%B3%BB)
9. [执行顺序与微任务队列](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#9-%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F%E4%B8%8E%E5%BE%AE%E4%BB%BB%E5%8A%A1%E9%98%9F%E5%88%97)
10. [常见陷阱](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#10-%E5%B8%B8%E8%A7%81%E9%99%B7%E9%98%B1)
11. [最佳实践](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#11-%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5)
12. [实战模式](JavaScript%20Promise%20%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97.md#12-%E5%AE%9E%E6%88%98%E6%A8%A1%E5%BC%8F)

---

## 1\. 什么是 Promise

Promise 是 JavaScript 中表示**异步操作最终结果**的对象。它代表一个"承诺"：现在不知道结果，但将来某个时刻会知道（成功或失败）。

**引入 Promise 的原因**：解决回调地狱（Callback Hell）。

```javascript
// 回调地狱：嵌套难以维护
getUser(id, function(user) {
  getOrders(user.id, function(orders) {
    getOrderDetail(orders[0].id, function(detail) {
      // 越来越深...
    }, handleError);
  }, handleError);
}, handleError);

// Promise 链：线性、清晰
getUser(id)
  .then(user => getOrders(user.id))
  .then(orders => getOrderDetail(orders[0].id))
  .then(detail => console.log(detail))
  .catch(handleError);

```

---

## 2\. Promise 的三种状态

| 状态  | 英文        | 含义          | 能否转换                      |
| --- | --------- | ----------- | ------------------------- |
| 等待中 | pending   | 初始状态，操作尚未完成 | 可以 → fulfilled 或 rejected |
| 已兑现 | fulfilled | 操作成功完成      | 不可逆                       |
| 已拒绝 | rejected  | 操作失败        | 不可逆                       |

```
pending ──→ fulfilled
       └──→ rejected

```

**关键规则**：

- 状态一旦变为 `fulfilled` 或 `rejected`，就**永远不会再改变**
- 一个 Promise 只能被 resolve 或 reject **一次**，后续调用无效
- `fulfilled` 和 `rejected` 统称为 `settled`（已落定）

```javascript
const p = new Promise((resolve, reject) => {
  resolve('成功');   // 状态变为 fulfilled
  reject('失败');    // 这行被忽略，状态已确定
  resolve('再次');   // 同样被忽略
});

p.then(v => console.log(v)); // 输出: "成功"

```

---

## 3\. 创建 Promise

### 3.1 构造函数 `new Promise(executor)`

```javascript
const promise = new Promise(executor);

```

**参数**：

#### `executor` — `Function`

执行器函数，在构造 Promise 时**立即同步执行**（不是异步的）。

```
executor(resolve, reject) => void

```

| 参数      | 类型       | 作用                                     |
| ------- | -------- | -------------------------------------- |
| resolve | Function | 调用后将 Promise 状态设为 fulfilled，传入的值作为成功结果 |
| reject  | Function | 调用后将 Promise 状态设为 rejected，传入的值作为失败原因  |

```javascript
const p1 = new Promise((resolve, reject) => {
  // executor 是同步执行的
  console.log('executor 开始');      // 1. 先打印这里

  setTimeout(() => {
    const success = Math.random() > 0.5;
    if (success) {
      resolve('操作成功');             // 将 p1 变为 fulfilled
    } else {
      reject(new Error('操作失败'));   // 将 p1 变为 rejected
    }
  }, 1000);

  console.log('executor 结束');      // 2. 然后打印这里
});

console.log('Promise 已创建');       // 3. 最后打印这里（executor 同步执行）

```

#### `resolve(value)` 的特殊行为

`resolve` 传入的 `value` 会影响 Promise 的最终状态：

```javascript
// 情况1：传入普通值 → 直接 fulfilled
resolve(42);
resolve('hello');
resolve({ data: [] });

// 情况2：传入另一个 Promise → 状态跟随那个 Promise
const inner = new Promise(resolve => setTimeout(() => resolve('inner'), 1000));
resolve(inner);  // p1 会等待 inner 完成，然后跟随其状态

// 情况3：传入 thenable 对象（有 .then 方法的对象）→ 跟随 thenable
resolve({
  then(resolve, reject) {
    resolve('thenable result');
  }
});

// 情况4：传入 undefined
resolve();       // fulfilled，值为 undefined

```

#### executor 中抛出异常

```javascript
const p = new Promise((resolve, reject) => {
  throw new Error('executor 中的错误');
  // 等价于 reject(new Error('executor 中的错误'))
});

p.catch(err => console.log(err.message)); // "executor 中的错误"

// 注意：只有同步抛出才会被捕获！
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    throw new Error('异步抛出');  // 不会被 Promise 捕获，会变成未处理的异常！
  }, 100);
});

```

---

## 4\. 实例方法

### 4.1 `.then()`

`.then()` 是 Promise 最核心的方法，用于注册成功和失败的回调。

```javascript
promise.then(onFulfilled, onRejected)

```

**参数**：

#### `onFulfilled` — `Function | null | undefined`

Promise 变为 `fulfilled` 时调用的函数。

```
onFulfilled(value) => any

```

| 内容       | 说明                                 |
| -------- | ---------------------------------- |
| 参数 value | Promise resolve 时传入的值              |
| 返回值      | 决定 .then() 返回的新 Promise 的状态（见下方详解） |
| 若传入非函数   | 会被忽略，值透传到下一个 .then()               |

#### `onRejected` — `Function | null | undefined`

Promise 变为 `rejected` 时调用的函数。

```
onRejected(reason) => any

```

| 内容        | 说明                                 |
| --------- | ---------------------------------- |
| 参数 reason | Promise reject 时传入的值（通常是 Error 对象） |
| 返回值       | 同样决定新 Promise 的状态                  |
| 若传入非函数    | 会被忽略，拒绝原因透传到下一个 .catch()           |

#### 返回值规则（重要！）

`.then()` **总是返回一个新的 Promise**，新 Promise 的状态取决于回调函数的返回值：

```javascript
const p = Promise.resolve(1);

// 规则1：回调返回普通值 → 新 Promise fulfilled，值为该返回值
p.then(v => v + 1)                    // fulfilled(2)
 .then(v => console.log(v));          // 输出: 2

// 规则2：回调返回 Promise → 新 Promise 跟随该 Promise
p.then(v => Promise.resolve(v * 10)) // 返回的 Promise fulfilled(10)
 .then(v => console.log(v));         // 输出: 10

p.then(v => Promise.reject('error')) // 返回的 Promise rejected('error')
 .catch(e => console.log(e));        // 输出: "error"

// 规则3：回调中抛出异常 → 新 Promise rejected，reason 为该异常
p.then(v => { throw new Error('oops'); })
 .catch(e => console.log(e.message)); // 输出: "oops"

// 规则4：回调返回 undefined（没有 return 语句）→ fulfilled(undefined)
p.then(v => { console.log(v); })     // 没有返回值
 .then(v => console.log(v));         // 输出: undefined

// 规则5：onFulfilled 是非函数 → 值透传
p.then(null)                         // 透传
 .then(null)                         // 透传
 .then(v => console.log(v));         // 输出: 1

```

#### 完整示例

```javascript
fetch('/api/user')
  .then(
    // onFulfilled：请求成功
    (response) => {
      console.log('状态码:', response.status);
      return response.json(); // 返回新 Promise
    },
    // onRejected：网络错误（不推荐在这里处理，推荐用 .catch()）
    (networkError) => {
      console.error('网络错误:', networkError);
      throw networkError; // 重新抛出，继续传递
    }
  )
  .then(data => {
    console.log('用户数据:', data);
  });

```

---

### 4.2 `.catch()`

`.catch()` 是 `.then(null, onRejected)` 的语法糖，专门用于捕获错误。

```javascript
promise.catch(onRejected)
// 完全等价于
promise.then(undefined, onRejected)

```

**参数**：

#### `onRejected` — `Function`

```
onRejected(reason) => any

```

| 内容        | 说明                           |
| --------- | ---------------------------- |
| 参数 reason | 拒绝原因，通常是 Error 实例            |
| 返回值       | 决定 .catch() 返回的新 Promise 的状态 |

**关键**：`.catch()` 返回的也是新 Promise，可以继续链式调用。

```javascript
// 错误恢复：在 catch 中返回值，可以从错误中"恢复"
Promise.reject(new Error('数据库连接失败'))
  .catch(err => {
    console.log('错误:', err.message);
    return '使用缓存数据'; // 返回备用值，链式继续为 fulfilled 状态
  })
  .then(data => {
    console.log('数据:', data); // 输出: "使用缓存数据"
  });

// 错误传递：在 catch 中继续抛出，传递给下一个 catch
Promise.reject(new Error('原始错误'))
  .catch(err => {
    console.log('第一个 catch:', err.message);
    throw new Error('包装后的错误'); // 继续传递
  })
  .catch(err => {
    console.log('第二个 catch:', err.message); // 捕获包装后的错误
  });

```

**为何推荐用 `.catch()` 而不是 `.then()` 的第二个参数**：

```javascript
// 问题：.then(onFulfilled, onRejected) 中，onRejected 无法捕获 onFulfilled 中的错误
promise
  .then(
    data => { throw new Error('onFulfilled 中出错'); }, // 这个错误...
    err => console.log('这里捕获不到上面的错误')        // ...不会到这里
  );

// 推荐：.catch() 放在链末尾，可以捕获整条链中的所有错误
promise
  .then(data => { throw new Error('任何地方的错误'); })
  .then(data => { /* ... */ })
  .catch(err => console.log('统一捕获:', err.message)); // 能捕获上面任意一步的错误

```

---

### 4.3 `.finally()`

无论 Promise 成功还是失败，都会执行的回调。ES2018 引入。

```javascript
promise.finally(onFinally)

```

**参数**：

#### `onFinally` — `Function`

```
onFinally() => any

```

| 内容           | 说明                               |
| ------------ | -------------------------------- |
| 参数           | **无参数**（无法获知 Promise 的结果或原因）     |
| 返回值（普通值）     | 被忽略，原 Promise 的值或原因会透传           |
| 返回值（Promise） | 等待该 Promise，若它 rejected 则覆盖原来的状态 |

```javascript
// 透传行为演示
Promise.resolve('成功的值')
  .finally(() => {
    console.log('finally 执行了');
    return '这个返回值会被忽略'; // 被忽略
  })
  .then(v => console.log(v)); // 输出: "成功的值"（透传）

Promise.reject(new Error('失败原因'))
  .finally(() => {
    console.log('finally 也执行了');
    // 不 return 任何东西
  })
  .catch(e => console.log(e.message)); // 输出: "失败原因"（透传）

// finally 返回 rejected Promise 会覆盖原状态
Promise.resolve('原来的成功值')
  .finally(() => Promise.reject(new Error('finally 中的错误')))
  .catch(e => console.log(e.message)); // 输出: "finally 中的错误"

```

**典型用途：资源清理**

```javascript
let connection;

getDbConnection()
  .then(conn => {
    connection = conn;
    return conn.query('SELECT * FROM users');
  })
  .then(users => {
    console.log(users);
  })
  .catch(err => {
    console.error('查询失败:', err);
  })
  .finally(() => {
    // 无论成功还是失败，都关闭连接
    if (connection) connection.close();
  });

```

---

## 5\. 静态方法

### 5.1 `Promise.resolve()`

创建一个**立即 fulfilled** 的 Promise。

```javascript
Promise.resolve(value)

```

**参数**：

#### `value` — `any`

| value 类型        | 返回结果                          |
| --------------- | ----------------------------- |
| 普通值（数字、字符串、对象等） | 返回 fulfilled(value) 的 Promise |
| 另一个 Promise 实例  | **直接返回该 Promise 本身**（不包装）     |
| Thenable 对象     | 返回跟随该 thenable 状态的 Promise    |
| 无参数 / undefined | 返回 fulfilled(undefined)       |

```javascript
// 普通值
Promise.resolve(42).then(v => console.log(v));         // 42
Promise.resolve('hello').then(v => console.log(v));    // "hello"

// 传入 Promise → 返回同一个对象
const original = new Promise(resolve => resolve(1));
const wrapped = Promise.resolve(original);
console.log(original === wrapped); // true！不会创建新 Promise

// 传入 thenable
Promise.resolve({
  then(resolve) { resolve('thenable value'); }
}).then(v => console.log(v)); // "thenable value"

// 常见用途：将同步值包装为 Promise，统一异步接口
function getData(id) {
  if (cache.has(id)) {
    return Promise.resolve(cache.get(id)); // 统一返回 Promise
  }
  return fetch(`/api/data/${id}`).then(r => r.json());
}

```

---

### 5.2 `Promise.reject()`

创建一个**立即 rejected** 的 Promise。

```javascript
Promise.reject(reason)

```

**参数**：

#### `reason` — `any`

拒绝原因，**强烈建议传入 `Error` 实例**（保留调用栈信息）。

```javascript
// 推荐：传入 Error 实例
Promise.reject(new Error('出错了'))
  .catch(err => console.log(err.stack)); // 包含完整调用栈

// 不推荐：传入字符串（没有调用栈）
Promise.reject('出错了')
  .catch(reason => console.log(reason)); // 只有字符串

// 注意：与 Promise.resolve 不同，传入 Promise 不会跟随，而是直接作为 reason
const inner = Promise.resolve('inner');
Promise.reject(inner)
  .catch(reason => {
    console.log(reason === inner); // true，inner 被当作 reason，不会解包
  });

```

---

### 5.3 `Promise.all()`

等待**所有** Promise 成功，任意一个失败则立即失败。

```javascript
Promise.all(iterable)

```

**参数**：

#### `iterable` — `Iterable`

包含 Promise（或任意值）的可迭代对象（通常是数组）。

- 非 Promise 值会被 `Promise.resolve()` 包装
- 空数组 `[]` 返回 `fulfilled([])`

**返回值**：新 Promise

| 情况              | 结果                                                       |
| --------------- | -------------------------------------------------------- |
| 所有 Promise 成功   | fulfilled(\[result1, result2, ...\]) — 结果数组**顺序与输入一致**   |
| 任意一个 Promise 失败 | **立即** rejected(reason) — 第一个失败的原因，其余 Promise 继续执行但结果被忽略 |
| iterable 为空     | fulfilled(\[\])                                          |

```javascript
// 基础用法：并发请求多个接口
const [user, orders, messages] = await Promise.all([
  fetch('/api/user').then(r => r.json()),
  fetch('/api/orders').then(r => r.json()),
  fetch('/api/messages').then(r => r.json()),
]);

// 结果顺序与输入顺序一致，与完成时间无关
Promise.all([
  new Promise(r => setTimeout(() => r('慢'), 1000)),
  new Promise(r => setTimeout(() => r('快'), 100)),
]).then(([slow, fast]) => {
  console.log(slow); // "慢"（第一个输入，虽然后完成）
  console.log(fast); // "快"（第二个输入）
});

// 任意失败则整体失败
Promise.all([
  Promise.resolve(1),
  Promise.reject(new Error('第二个失败了')),
  Promise.resolve(3), // 这个成功了，但结果被忽略
]).catch(err => console.log(err.message)); // "第二个失败了"

// 混合普通值
Promise.all([1, Promise.resolve(2), 'three'])
  .then(results => console.log(results)); // [1, 2, "three"]

```

---

### 5.4 `Promise.allSettled()`

等待**所有** Promise 落定（无论成功还是失败）。ES2020 引入。

```javascript
Promise.allSettled(iterable)

```

**参数**：同 `Promise.all()`。

**返回值**：`fulfilled(results)` — **永远不会 reject**。

`results` 是对象数组，每个对象的格式：

```javascript
// 成功时
{ status: 'fulfilled', value: any }

// 失败时
{ status: 'rejected', reason: any }

```

```javascript
const results = await Promise.allSettled([
  Promise.resolve('成功1'),
  Promise.reject(new Error('失败')),
  Promise.resolve('成功2'),
]);

results.forEach(result => {
  if (result.status === 'fulfilled') {
    console.log('成功:', result.value);
  } else {
    console.log('失败:', result.reason.message);
  }
});
// 成功: 成功1
// 失败: 失败
// 成功: 成功2

// 与 Promise.all 的对比：
// Promise.all     → 任意失败就整体失败（快速失败）
// Promise.allSettled → 等全部完成再汇总（全量结果）

```

**适用场景**：批量操作中需要知道每个操作的结果。

```javascript
// 批量上传文件，统计成功/失败数量
const uploadResults = await Promise.allSettled(
  files.map(file => uploadFile(file))
);

const succeeded = uploadResults.filter(r => r.status === 'fulfilled').length;
const failed = uploadResults.filter(r => r.status === 'rejected').length;
console.log(`上传完成：${succeeded} 成功，${failed} 失败`);

```

---

### 5.5 `Promise.any()`

返回**第一个成功**的 Promise，全部失败才失败。ES2021 引入。

```javascript
Promise.any(iterable)

```

**参数**：同 `Promise.all()`。

**返回值**：新 Promise

| 情况          | 结果                                  |
| ----------- | ----------------------------------- |
| 任意一个成功      | 立即 fulfilled(value) — 第一个成功的值       |
| 全部失败        | rejected(AggregateError) — 包含所有失败原因 |
| iterable 为空 | rejected(AggregateError)            |

```javascript
// 基础用法：多个数据源，取最快成功的那个
const data = await Promise.any([
  fetch('https://cdn1.example.com/data').then(r => r.json()),
  fetch('https://cdn2.example.com/data').then(r => r.json()),
  fetch('https://cdn3.example.com/data').then(r => r.json()),
]); // 哪个 CDN 最快返回就用哪个

// 全部失败时的错误
try {
  await Promise.any([
    Promise.reject(new Error('失败1')),
    Promise.reject(new Error('失败2')),
  ]);
} catch (err) {
  console.log(err instanceof AggregateError); // true
  console.log(err.message);                  // "All promises were rejected"
  console.log(err.errors);                   // [Error: 失败1, Error: 失败2]
}

```

---

### 5.6 `Promise.race()`

返回**第一个落定**（无论成功还是失败）的 Promise 的结果。

```javascript
Promise.race(iterable)

```

**参数**：同 `Promise.all()`。

**返回值**：新 Promise，状态与第一个落定的 Promise 相同。

| 情况               | 结果               |
| ---------------- | ---------------- |
| 第一个落定是 fulfilled | fulfilled(value) |
| 第一个落定是 rejected  | rejected(reason) |
| iterable 为空      | 永远 pending（!）    |

```javascript
// 超时控制：最经典的用法
function withTimeout(promise, ms) {
  const timeout = new Promise((_, reject) =>
    setTimeout(() => reject(new Error(`超时 ${ms}ms`)), ms)
  );
  return Promise.race([promise, timeout]);
}

try {
  const result = await withTimeout(fetch('/api/slow'), 3000);
} catch (err) {
  console.log(err.message); // 如果超时: "超时 3000ms"
}

// 注意：race 不会取消"落败"的 Promise，它们仍在后台执行
// 要真正取消，需要使用 AbortController

```

**四个组合方法对比**：

| 方法                 | 成功条件    | 失败条件       | 返回       | 引入版本   |
| ------------------ | ------- | ---------- | -------- | ------ |
| Promise.all        | 全部成功    | 任意失败（快速失败） | 所有结果数组   | ES2015 |
| Promise.allSettled | 全部落定    | 永不失败       | 所有状态对象数组 | ES2020 |
| Promise.any        | 任意成功    | 全部失败       | 第一个成功值   | ES2021 |
| Promise.race       | 第一个落定成功 | 第一个落定失败    | 第一个落定值   | ES2015 |
| Promise.try        | 回调正常返回  | 回调抛出异常     | 包装回调结果   | ES2026 |

---

### 5.7 `Promise.withResolvers()`

返回一个包含 Promise 及其 resolve/reject 函数的对象，让你在 Promise 外部控制其状态。ES2024 引入。

```javascript
Promise.withResolvers()

```

**返回值**：`{ promise, resolve, reject }`

```javascript
// 传统写法：需要在 executor 内部保存引用
let resolve, reject;
const promise = new Promise((res, rej) => {
  resolve = res;
  reject = rej;
});

// withResolvers 写法：更简洁
const { promise, resolve, reject } = Promise.withResolvers();

// 在任意地方控制 Promise
document.getElementById('btn').addEventListener('click', () => {
  resolve('用户点击了按钮');
});

const result = await promise;
console.log(result);

```

### 5.8 `Promise.try()`

将任意类型的回调（同步或异步、返回值或抛出异常）统一包装成 Promise。ES2026 引入（Baseline 2025）。

```javascript
Promise.try(func)
Promise.try(func, arg1, arg2, ...argN)

```

**参数**：

| 参数          | 类型       | 说明                              |
| ----------- | -------- | ------------------------------- |
| func        | Function | 同步调用的回调函数，可以返回值、抛出异常或返回 Promise |
| arg1...argN | any      | 传给 func 的参数列表                   |

**返回值**：新 Promise

- 若 `func` 同步返回值 → 已 fulfilled 的 Promise
- 若 `func` 同步抛出异常 → 已 rejected 的 Promise
- 若 `func` 返回 Promise → 跟随该 Promise

```javascript
// 统一处理同步和异步回调
function doSomething(action) {
  return Promise.try(action)
    .then(result => console.log(result))
    .catch(err => console.error(err))
    .finally(() => console.log('完成'));
}

doSomething(() => '同步结果');                  // 同步返回值
doSomething(() => { throw new Error('同步错误'); }); // 同步抛出
doSomething(async () => '异步结果');            // 返回 Promise

// 对比旧写法：
// Promise.resolve(func()) 不能捕获同步抛出
// new Promise(resolve => resolve(func())) 才等价，但更繁琐

```

**典型用途**：消除回调是同步还是异步的不确定性，统一用 Promise 链处理。

---

## 6\. Promise 链式调用

### 6.1 链式调用的工作原理

每个 `.then()` / `.catch()` / `.finally()` 都返回一个**新的 Promise**，因此可以无限链接。

```javascript
Promise.resolve(1)
  .then(v => v + 1)          // 返回 fulfilled(2)
  .then(v => v * 3)          // 返回 fulfilled(6)
  .then(v => {
    if (v > 5) throw new Error('太大了');
  })                          // 返回 rejected(Error)
  .catch(err => {
    console.log(err.message); // "太大了"
    return 0;                 // 从错误中恢复，返回 fulfilled(0)
  })
  .then(v => console.log(v)); // 0

```

### 6.2 常见错误：不返回内层 Promise

```javascript
// 错误：没有 return，导致链断裂
fetch('/api/user')
  .then(response => {
    response.json().then(data => {  // 这里没有 return！
      console.log(data);
    });
    // 这个 .then 回调没有明确返回，
    // 所以下一个 .then 不会等待 response.json() 完成
  })
  .then(() => {
    // 这里可能在 data 被打印之前就执行了
  });

// 正确：return 内层 Promise
fetch('/api/user')
  .then(response => {
    return response.json(); // 必须 return！
  })
  .then(data => {
    console.log(data); // 保证在数据解析后执行
  });

```

---

## 7\. 错误处理模式

### 7.1 链末捕获（推荐）

```javascript
doStep1()
  .then(doStep2)
  .then(doStep3)
  .catch(err => {
    // 捕获以上任意一步的错误
    console.error('某一步出错了:', err);
  });

```

### 7.2 局部捕获（错误不扩散）

```javascript
doStep1()
  .then(result1 =>
    doStep2(result1).catch(err => {
      // 只捕获 step2 的错误，提供默认值
      console.warn('step2 失败，使用默认值');
      return defaultValue; // 继续链式
    })
  )
  .then(doStep3)
  .catch(err => {
    // 只有 step1 和 step3 的错误到达这里
  });

```

### 7.3 错误转换

```javascript
function getUser(id) {
  return fetch(`/api/users/${id}`)
    .then(response => {
      if (!response.ok) {
        // 将 HTTP 错误转换为有意义的自定义错误
        throw new UserNotFoundError(`用户 ${id} 不存在，状态码: ${response.status}`);
      }
      return response.json();
    });
}

```

### 7.4 未处理的 Promise 拒绝

```javascript
// 在 Node.js 中监听未处理的 rejection
process.on('unhandledRejection', (reason, promise) => {
  console.error('未处理的 Promise 拒绝:', reason);
});

// 在浏览器中
window.addEventListener('unhandledrejection', event => {
  console.error('未处理的 Promise 拒绝:', event.reason);
  event.preventDefault(); // 阻止默认的控制台错误
});

```

---

## 8\. async / await 与 Promise 的关系

`async/await` 是 Promise 的语法糖，底层仍然是 Promise。

### 8.1 对应关系

```javascript
// Promise 写法
function fetchUser(id) {
  return fetch(`/api/users/${id}`)
    .then(res => res.json())
    .then(user => {
      console.log(user.name);
      return user;
    })
    .catch(err => {
      console.error(err);
      throw err;
    });
}

// async/await 写法（等价）
async function fetchUser(id) {
  try {
    const res = await fetch(`/api/users/${id}`);
    const user = await res.json();
    console.log(user.name);
    return user; // async 函数自动包装为 Promise.resolve(user)
  } catch (err) {
    console.error(err);
    throw err; // async 函数中的 throw 等价于 Promise.reject(err)
  }
}

```

### 8.2 async 函数的返回值

```javascript
async function f1() { return 42; }
// 等价于
function f1() { return Promise.resolve(42); }

async function f2() { throw new Error('err'); }
// 等价于
function f2() { return Promise.reject(new Error('err')); }

async function f3() { return Promise.resolve(42); }
// 返回 fulfilled(42)，不会双重包装

```

### 8.3 并发控制

```javascript
// 错误：串行执行（每个 await 等待上一个完成）
async function serial() {
  const a = await fetch('/api/a');  // 先等这个
  const b = await fetch('/api/b');  // 再等这个（总时间 = a + b）
  return [a, b];
}

// 正确：并发执行
async function concurrent() {
  const [a, b] = await Promise.all([
    fetch('/api/a'),
    fetch('/api/b'),
  ]); // 总时间 = max(a, b)
  return [a, b];
}

// 先触发，后等待
async function concurrent2() {
  const promiseA = fetch('/api/a'); // 立即触发
  const promiseB = fetch('/api/b'); // 立即触发（不加 await）
  const a = await promiseA;         // 然后等待
  const b = await promiseB;
  return [a, b];
}

```

---

## 9\. 执行顺序与微任务队列

Promise 的回调作为**微任务（Microtask）执行，优先于宏任务（Macrotask）**。

```javascript
console.log('1. 同步代码 开始');

setTimeout(() => console.log('5. 宏任务 (setTimeout)'), 0);

Promise.resolve()
  .then(() => console.log('3. 微任务 1'))
  .then(() => console.log('4. 微任务 2'));

console.log('2. 同步代码 结束');

// 输出顺序：
// 1. 同步代码 开始
// 2. 同步代码 结束
// 3. 微任务 1
// 4. 微任务 2
// 5. 宏任务 (setTimeout)

```

### 执行模型

```
同步代码（调用栈）
    ↓ 清空
微任务队列（Promise.then/catch/finally）
    ↓ 全部清空
宏任务队列（setTimeout, setInterval, I/O...）
    ↓ 取一个执行
微任务队列（处理本轮宏任务产生的微任务）
    ↓ 全部清空
...

```

```javascript
// 嵌套的微任务
Promise.resolve().then(() => {
  console.log('微任务 A');
  Promise.resolve().then(() => {
    console.log('微任务 A 的子任务'); // 在 B 之前！
  });
}).then(() => {
  console.log('微任务 B');
});

// 输出：
// 微任务 A
// 微任务 A 的子任务
// 微任务 B

```

---

## 10\. 常见陷阱

### 陷阱1：在循环中使用 Promise

```javascript
const ids = [1, 2, 3, 4, 5];

// 错误：forEach 不等待 async 回调
ids.forEach(async (id) => {
  const data = await fetchData(id); // forEach 不 await 这个
  process(data);
});
// 以上代码立即结束，所有请求"发出"但不等待

// 正确：使用 Promise.all（并发）
await Promise.all(ids.map(id => fetchData(id).then(process)));

// 正确：使用 for...of（串行，保证顺序）
for (const id of ids) {
  const data = await fetchData(id);
  process(data);
}

```

### 陷阱2：Promise 构造函数中的异步 throw

```javascript
// 错误：异步抛出不会被 Promise 捕获
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    throw new Error('异步错误'); // 未捕获异常！会崩溃
  }, 100);
});

// 正确：必须调用 reject
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    try {
      // ...
    } catch (err) {
      reject(err); // 必须手动 reject
    }
  }, 100);
});

```

### 陷阱3：忘记 return

```javascript
// 陷阱：两个独立的 Promise 链，不是一个链
function processData() {
  fetch('/api/data')
    .then(r => r.json())
    .then(data => save(data)); // 这里忘记 return
  // 函数返回 undefined，调用方无法知道何时完成
}

// 正确
function processData() {
  return fetch('/api/data')   // return！
    .then(r => r.json())
    .then(data => save(data));
}

```

### 性能陷阱4：不必要的 new Promise 包装

```javascript
// 反模式：Promise 构造函数反模式（Explicit Promise Construction Anti-Pattern）
function getUser(id) {
  return new Promise((resolve, reject) => {
    fetch(`/api/users/${id}`)  // fetch 本身已经返回 Promise！
      .then(r => r.json())
      .then(resolve)           // 多此一举
      .catch(reject);          // 多此一举
  });
}

// 正确：直接返回 Promise 链
function getUser(id) {
  return fetch(`/api/users/${id}`).then(r => r.json());
}

```

### 陷阱5：吞掉错误

```javascript
// 危险：空的 catch 把错误吞掉
promise.catch(() => {}); // 错误消失，无法调试

// 至少记录一下
promise.catch(err => console.error('Promise 错误:', err));

```

---

## 11\. 最佳实践

### 1\. 始终处理拒绝

```javascript
// 每个 Promise 链都应该有错误处理
somePromise()
  .then(handleSuccess)
  .catch(handleError); // 不能省

```

### 2\. 避免嵌套，保持链式

```javascript
// 避免嵌套 Promise
// 坏
p1.then(r1 => {
  p2(r1).then(r2 => {
    p3(r2).then(r3 => {
      // 嵌套地狱回归了
    });
  });
});

// 好：平铺链式
p1.then(r1 => p2(r1))
  .then(r2 => p3(r2))
  .then(r3 => { /* 处理 r3 */ })
  .catch(handleError);

```

### 3\. reject 时传入 Error 对象

```javascript
// 坏
reject('something went wrong');
reject({ code: 500, message: 'error' });

// 好：保留调用栈，便于调试
reject(new Error('something went wrong'));
reject(Object.assign(new Error('error'), { code: 500 }));

```

### 4\. 用 Promise.all 做并发，而非串行

```javascript
// 独立的异步操作应该并发
const [user, config] = await Promise.all([getUser(), getConfig()]);

```

### 5\. 使用 AbortController 取消请求

```javascript
const controller = new AbortController();

const promise = fetch('/api/data', {
  signal: controller.signal,
});

// 取消
setTimeout(() => controller.abort(), 3000);

try {
  const data = await promise;
} catch (err) {
  if (err.name === 'AbortError') {
    console.log('请求被取消');
  }
}

```

### 6\. 注意 finally 的透传特性

```javascript
// finally 中的普通返回值被忽略，但不要依赖这一"隐式"行为
// 如果在 finally 中需要修改结果，使用 then

// 如果 finally 中有异步操作，必须 return Promise
.finally(async () => {
  await cleanup(); // 必须 return 才等待！
})
// 应改为：
.finally(() => cleanup()) // 返回 cleanup() 的 Promise

```

---

## 12\. 实战模式

### 12.1 重试机制

```javascript
/**
 * 带重试的 Promise 执行器
 * @param {Function} fn - 返回 Promise 的函数
 * @param {number} retries - 最大重试次数
 * @param {number} delay - 重试间隔（ms）
 */
function retry(fn, retries = 3, delay = 1000) {
  return fn().catch(err => {
    if (retries <= 0) throw err;
    console.log(`失败，${delay}ms 后重试，剩余次数: ${retries}`);
    return new Promise(resolve => setTimeout(resolve, delay))
      .then(() => retry(fn, retries - 1, delay * 2)); // 指数退避
  });
}

// 使用
const data = await retry(() => fetch('/api/unstable').then(r => r.json()));

```

### 12.2 并发限制

```javascript
/**
 * 限制并发数量的 Promise 执行器
 * @param {Array} tasks - 任务数组（每个元素是返回 Promise 的函数）
 * @param {number} concurrency - 最大并发数
 */
async function limitConcurrency(tasks, concurrency) {
  const results = [];
  const executing = new Set();

  for (const task of tasks) {
    const promise = task().then(result => {
      executing.delete(promise);
      return result;
    });
    executing.add(promise);
    results.push(promise);

    if (executing.size >= concurrency) {
      await Promise.race(executing); // 等待最快完成的那个
    }
  }

  return Promise.all(results);
}

// 使用：同时最多 3 个请求
const results = await limitConcurrency(
  urls.map(url => () => fetch(url).then(r => r.json())),
  3
);

```

### 12.3 超时 + 取消

```javascript
function fetchWithTimeout(url, ms = 5000) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), ms);

  return fetch(url, { signal: controller.signal })
    .finally(() => clearTimeout(timeoutId)); // 成功后清除定时器
}

```

### 12.4 缓存 Promise（防止重复请求）

```javascript
const cache = new Map();

function cachedFetch(url) {
  if (cache.has(url)) {
    return cache.get(url); // 返回同一个 Promise（即使还没完成）
  }

  const promise = fetch(url)
    .then(r => r.json())
    .catch(err => {
      cache.delete(url); // 失败时清除缓存，允许重试
      throw err;
    });

  cache.set(url, promise);
  return promise;
}

// 即使短时间内被调用多次，也只发出一个 HTTP 请求
cachedFetch('/api/config');
cachedFetch('/api/config'); // 返回同一个 Promise

```

### 12.5 事件转 Promise

```javascript
// 将事件监听器转换为 Promise
function waitForEvent(emitter, event, errorEvent = 'error') {
  return new Promise((resolve, reject) => {
    const onSuccess = (data) => {
      emitter.removeListener(errorEvent, onError);
      resolve(data);
    };
    const onError = (err) => {
      emitter.removeListener(event, onSuccess);
      reject(err);
    };
    emitter.once(event, onSuccess);
    emitter.once(errorEvent, onError);
  });
}

// 使用
const data = await waitForEvent(stream, 'data');
await waitForEvent(connection, 'open');

```

### 12.6 顺序执行任务队列

```javascript
// 将一组异步任务按顺序执行，并收集结果
function sequentialPromises(tasks) {
  return tasks.reduce(
    (chain, task) => chain.then(results =>
      task().then(result => [...results, result])
    ),
    Promise.resolve([])
  );
}

const results = await sequentialPromises([
  () => fetch('/api/step1').then(r => r.json()),
  () => fetch('/api/step2').then(r => r.json()),
  () => fetch('/api/step3').then(r => r.json()),
]);

```

---

## 快速参考卡

```
创建
  new Promise((resolve, reject) => {...})   手动创建
  Promise.resolve(value)                    立即成功
  Promise.reject(reason)                    立即失败
  Promise.withResolvers()                   外部控制

实例方法
  .then(onFulfilled, onRejected?)           成功/失败回调
  .catch(onRejected)                        等价 .then(null, fn)
  .finally(onFinally)                       无论如何都执行

组合方法
  Promise.all([...])                        全成功 / 一失败立即失败
  Promise.allSettled([...])                 全落定 / 永不失败
  Promise.any([...])                        一成功 / 全失败才失败
  Promise.race([...])                       第一个落定（成功或失败）
  Promise.try(fn, ...args)                  包装任意回调为 Promise（ES2026）

```

---

## 最佳实践

**优先用 `async/await` 而非 `.then` 链**：`async/await` 使控制流更线性，错误处理用 `try/catch` 比 `.catch` 更直观，尤其是多个顺序异步操作时。

**并发请求用 `Promise.allSettled` 代替 `Promise.all`**：`Promise.all` 中任一失败即短路，适合"全部成功才有意义"的场景；`Promise.allSettled` 等所有请求完成后检查每个结果，适合批量操作需要汇总失败列表的场景。

**Promise 链末尾始终加 `.catch`**：未捕获的 Promise 拒绝在 Node.js 中会导致进程崩溃（`--unhandled-rejections=throw`），在浏览器中触发 `unhandledrejection` 事件。

**用 `Promise.race` 实现超时控制**：

```js
const timeout = new Promise((_, reject) =>
  setTimeout(() => reject(new Error('Timeout')), 5000)
);
const result = await Promise.race([fetch(url), timeout]);

```

**避免在循环中顺序 `await`**：`for` 循环中 `await` 会逐个等待，所有请求串行执行；改用 `Promise.all` 并发：

```js
// 差：串行，总耗时 = sum(各请求时间)
for (const url of urls) await fetch(url);

// 好：并发，总耗时 ≈ max(各请求时间)
await Promise.all(urls.map(url => fetch(url)));

```

---

## 常见陷阱

### 陷阱：`forEach` 中 `await` 不等待内部 Promise

**现象：** `arr.forEach(async item => { await process(item) })` 执行后数据没有处理完，函数已经返回。  
**原因：** `forEach` 不处理回调的返回值（Promise），内部 `await` 只在回调协程内暂停，外层 `forEach` 继续执行。  
**解决：** 改用 `for...of` 或 `Promise.all(arr.map(async item => { await process(item) }))`。

### 陷阱：`async` 函数总返回 Promise，普通 `return` 值也被包裹

**现象：** `const val = myAsyncFn()` 以为得到返回值，实际是 Promise 对象。  
**原因：** `async` 函数的返回值自动包在 `Promise.resolve()` 中，调用方必须 `await`。  
**解决：** 调用 `async` 函数时始终 `await`，或用 `.then()` 处理结果。

### 陷阱：Promise 构造函数中同步抛出的错误不被捕获

**现象：** `new Promise(() => { throw new Error('sync') })` 中抛出的错误没有被外部 `.catch` 捕获。  
**原因：** Promise 构造函数的 executor 中同步抛出会被转换为拒绝，`.catch` 可以捕获；但若在 `setTimeout` 等异步回调中抛出，则脱离 Promise 链，变为未捕获异常。  
**解决：** 在 executor 的异步回调中用 `reject(error)` 而非 `throw`。

---

## 参见

- [JavaScript入门](https://blog.vercanti.com/javascript-ru-men/)
- [asyncio异步编程完全指南](https://blog.vercanti.com/asyncio-yi-bu-bian-cheng-wan-quan-zhi-nan/)
- [Axios完全指南](https://blog.vercanti.com/axios-wan-quan-zhi-nan/)
- [TypeScript完全指南](https://blog.vercanti.com/typescript-wan-quan-zhi-nan/)