📚 目录

  1. Promise 是什么?为什么需要它?
  2. Promise 的三种状态
  3. Promise 基础用法
  4. Promise 的核心方法
  5. Promise 的静态方法详解
  6. Promise 链式调用深度解析
  7. Promise 的错误处理机制
  8. Promise 与事件循环(微任务机制)
  9. async/await:Promise 的语法糖
  10. Promise 实战应用场景
  11. Promise 常见陷阱与最佳实践
  12. 手写 Promise(深入理解原理)
  13. 总结与知识图谱

1. Promise 是什么?为什么需要它?

1.1 JavaScript 的异步问题

在 JavaScript 中,很多操作是异步的,比如:

  • 网络请求(Ajax、Fetch)
  • 定时器(setTimeout、setInterval)
  • 文件读写(Node.js)
  • 数据库操作

异步操作的特点:不会立即返回结果,需要等待一段时间。

1.2 回调地狱(Callback Hell)

在 Promise 出现之前,我们使用回调函数来处理异步操作:

// 传统回调方式:层层嵌套,难以维护
getUserInfo(userId, function(user) {
  getOrders(user.id, function(orders) {
    getOrderDetail(orders[0].id, function(detail) {
      getProductInfo(detail.productId, function(product) {
        console.log('最终获取到商品信息:', product);
        // 如果还有更多异步操作...继续嵌套...
      });
    });
  });
});

回调地狱的问题

  1. ❌ 代码横向发展,可读性差(“厄运金字塔”)
  2. ❌ 错误处理困难,每层都要处理错误
  3. ❌ 难以维护和调试
  4. ❌ 无法使用 try-catch 捕获错误

1.3 Promise 的解决方案

Promise 是一种异步编程的解决方案,让异步代码看起来更像同步代码:

// 使用 Promise:链式调用,清晰优雅
getUserInfo(userId)
  .then(user => getOrders(user.id))
  .then(orders => getOrderDetail(orders[0].id))
  .then(detail => getProductInfo(detail.productId))
  .then(product => {
    console.log('最终获取到商品信息:', product);
  })
  .catch(error => {
    console.error('任何一步出错都会被捕获:', error);
  });

Promise 的优势

  • ✅ 链式调用,代码扁平化
  • ✅ 统一的错误处理
  • ✅ 更好的语义和可读性
  • ✅ 方便组合多个异步操作

1.4 Promise 的本质

Promise 是一个承诺:我现在不知道结果,但我承诺未来会给你一个结果(成功或失败)。

// 形象理解:去餐厅点餐
// 1. 你点了一份餐(创建 Promise)
// 2. 服务员给你一个号码牌(Promise 对象)
// 3. 你可以先坐下等待(继续执行其他代码)
// 4. 餐做好了会叫你的号(Promise 状态改变,执行回调)
//    - 成功:你拿到了餐(fulfilled)
//    - 失败:餐卖完了(rejected)

2. Promise 的三种状态

Promise 对象有且只有三种状态

2.1 三种状态详解

// 1. pending(进行中):初始状态,既没有成功也没有失败
const promise1 = new Promise((resolve, reject) => {
  // 此时 Promise 处于 pending 状态
  console.log('正在执行异步操作...');
});

// 2. fulfilled(已成功):操作成功完成
const promise2 = new Promise((resolve, reject) => {
  resolve('成功的结果'); // 调用 resolve,状态变为 fulfilled
});

// 3. rejected(已失败):操作失败
const promise3 = new Promise((resolve, reject) => {
  reject('失败的原因'); // 调用 reject,状态变为 rejected
});

2.2 状态转换规则

pending ──resolve──> fulfilled(成功)
   │
   └──reject──> rejected(失败)

重要特性

  1. ✅ 状态只能从 pending 变为 fulfilledrejected
  2. ✅ 状态一旦改变,就永久保持,不会再变(状态凝固)
  3. ✅ 状态改变只有两种可能:
    • pendingfulfilled
    • pendingrejected

2.3 状态不可逆示例

const promise = new Promise((resolve, reject) => {
  resolve('成功了');
  reject('失败了');  // 这行不会执行,状态已经凝固
  resolve('再次成功'); // 这行也不会执行
});

promise.then(
  value => console.log(value),  // 输出:成功了
  reason => console.log(reason) // 不会执行
);

3. Promise 基础用法

3.1 创建 Promise

// 语法:new Promise(executor)
// executor:执行器函数,立即同步执行
const promise = new Promise((resolve, reject) => {
  // resolve:成功时调用的函数
  // reject:失败时调用的函数
  
  // 模拟异步操作
  setTimeout(() => {
    const success = Math.random() > 0.5;
    
    if (success) {
      resolve('操作成功!'); // 将结果传递给 then
    } else {
      reject('操作失败!');  // 将错误传递给 catch
    }
  }, 1000);
});

console.log('Promise 已创建'); // 这行会立即执行

关键点

  • new Promise() 的参数是一个执行器函数
  • 执行器函数立即同步执行
  • 执行器函数接收两个参数:resolvereject

3.2 使用 then() 方法

// then() 方法接收两个参数:成功回调和失败回调
promise.then(
  // 参数1:成功回调(可选)
  value => {
    console.log('成功:', value);
  },
  // 参数2:失败回调(可选)
  reason => {
    console.log('失败:', reason);
  }
);

3.3 使用 catch() 方法

// catch() 专门用于捕获错误,等价于 .then(null, onRejected)
promise
  .then(value => {
    console.log('成功:', value);
  })
  .catch(reason => {
    console.log('失败:', reason);
  });

3.4 使用 finally() 方法

// finally() 无论成功还是失败都会执行
promise
  .then(value => {
    console.log('成功:', value);
  })
  .catch(reason => {
    console.log('失败:', reason);
  })
  .finally(() => {
    console.log('无论成功失败,我都会执行');
    // 常用于:关闭加载状态、清理资源等
  });

3.5 完整示例:模拟网络请求

// 模拟一个网络请求函数
function fetchUser(userId) {
  return new Promise((resolve, reject) => {
    console.log('开始请求用户数据...');
    
    // 模拟网络延迟
    setTimeout(() => {
      if (userId > 0) {
        resolve({
          id: userId,
          name: '张三',
          age: 25
        });
      } else {
        reject('用户ID无效');
      }
    }, 1000);
  });
}

// 使用
fetchUser(1)
  .then(user => {
    console.log('用户数据:', user);
    // 输出:用户数据: { id: 1, name: '张三', age: 25 }
  })
  .catch(error => {
    console.error('请求失败:', error);
  })
  .finally(() => {
    console.log('请求结束');
  });

4. Promise 的核心方法

4.1 then() 方法详解

then() 是 Promise 最核心的方法,它的完整签名是:

promise.then(onFulfilled, onRejected)

关键特性

  1. then() 方法返回一个新的 Promise
  2. ✅ 支持链式调用
  3. ✅ 可以传递值到下一个 then()
// 示例:then() 的返回值
const promise = new Promise((resolve) => {
  resolve(1);
});

promise
  .then(value => {
    console.log(value); // 1
    return value + 1;   // 返回普通值,会被包装成 Promise
  })
  .then(value => {
    console.log(value); // 2
    return value + 1;
  })
  .then(value => {
    console.log(value); // 3
  });

then() 的四种返回情况

// 情况1:返回普通值
promise.then(value => {
  return 'hello'; // 会被包装成 Promise.resolve('hello')
});

// 情况2:返回 Promise 对象
promise.then(value => {
  return new Promise(resolve => {
    resolve('world');
  });
});

// 情况3:抛出错误
promise.then(value => {
  throw new Error('出错了'); // 会被包装成 Promise.reject(Error)
});

// 情况4:不返回值(返回 undefined)
promise.then(value => {
  console.log(value);
  // 没有 return,默认返回 Promise.resolve(undefined)
});

4.2 catch() 方法详解

catch()then(null, onRejected) 的语法糖:

// 这两种写法完全等价
promise.catch(error => console.error(error));
promise.then(null, error => console.error(error));

catch() 的强大之处

// catch() 可以捕获之前任何一步的错误
Promise.resolve()
  .then(() => {
    throw new Error('第1步出错');
  })
  .then(() => {
    console.log('第2步'); // 不会执行
  })
  .then(() => {
    console.log('第3步'); // 不会执行
  })
  .catch(error => {
    console.error('捕获到错误:', error.message);
    // 输出:捕获到错误:第1步出错
  });

catch() 也返回 Promise

Promise.reject('错误')
  .catch(error => {
    console.log('处理错误:', error);
    return '错误已修复'; // 返回新值,链条可以继续
  })
  .then(value => {
    console.log('继续执行:', value); // 输出:继续执行:错误已修复
  });

4.3 finally() 方法详解

finally() 是 ES2018 引入的方法,特点是:

// finally() 的特点
Promise.resolve('成功')
  .finally(() => {
    console.log('finally 执行');
    // 注意:finally 不接收任何参数
    // 无法知道 Promise 是成功还是失败
  })
  .then(value => {
    console.log(value); // 输出:成功
    // finally 不会改变 Promise 的值
  });

finally() 的典型应用

function fetchData() {
  // 显示加载状态
  showLoading();
  
  return fetch('/api/data')
    .then(response => response.json())
    .then(data => {
      // 处理数据
      return data;
    })
    .catch(error => {
      // 处理错误
      console.error(error);
    })
    .finally(() => {
      // 无论成功还是失败,都隐藏加载状态
      hideLoading();
    });
}

5. Promise 的静态方法详解

Promise 提供了多个静态方法,用于处理多个 Promise 的组合场景。

5.1 Promise.resolve()

快速创建一个成功的 Promise:

// 方式1:使用 Promise.resolve()
const promise1 = Promise.resolve('成功');

// 方式2:等价写法
const promise2 = new Promise(resolve => {
  resolve('成功');
});

// Promise.resolve() 的三种情况
// 情况1:参数是普通值
Promise.resolve('hello').then(value => {
  console.log(value); // hello
});

// 情况2:参数是 Promise 对象
const p = new Promise(resolve => resolve('world'));
Promise.resolve(p).then(value => {
  console.log(value); // world
});

// 情况3:参数是 thenable 对象(有 then 方法的对象)
const thenable = {
  then(resolve, reject) {
    resolve('thenable');
  }
};
Promise.resolve(thenable).then(value => {
  console.log(value); // thenable
});

5.2 Promise.reject()

快速创建一个失败的 Promise:

// 创建失败的 Promise
Promise.reject('错误原因')
  .catch(reason => {
    console.log(reason); // 错误原因
  });

// 注意:Promise.reject() 不会做特殊处理
// 即使参数是 Promise,也会原样传递
const p = Promise.resolve('成功');
Promise.reject(p)
  .catch(reason => {
    console.log(reason === p); // true
  });

5.3 Promise.all()

用途:并发执行多个 Promise,等待所有 Promise 都成功才成功。

// 语法
Promise.all([promise1, promise2, promise3])

特点

  • ✅ 所有 Promise 都成功,返回所有结果的数组
  • ❌ 任何一个 Promise 失败,立即返回失败
// 示例:同时请求多个接口
const promise1 = fetch('/api/user');
const promise2 = fetch('/api/orders');
const promise3 = fetch('/api/products');

Promise.all([promise1, promise2, promise3])
  .then(([user, orders, products]) => {
    console.log('用户信息:', user);
    console.log('订单列表:', orders);
    console.log('商品列表:', products);
    // 三个请求都成功,才会执行这里
  })
  .catch(error => {
    console.error('有请求失败:', error);
    // 任何一个请求失败,都会执行这里
  });

实用案例:批量上传文件

function uploadFiles(files) {
  const uploadPromises = files.map(file => {
    return fetch('/api/upload', {
      method: 'POST',
      body: file
    });
  });
  
  return Promise.all(uploadPromises)
    .then(results => {
      console.log('所有文件上传成功', results);
    })
    .catch(error => {
      console.error('有文件上传失败', error);
    });
}

5.4 Promise.race()

用途:并发执行多个 Promise,返回最先完成的那个结果(无论成功还是失败)。

// 语法
Promise.race([promise1, promise2, promise3])

特点

  • ⚡ 谁先完成(成功或失败),就返回谁的结果
  • ⚡ 其他 Promise 继续执行,但结果被忽略
// 示例:请求超时控制
function fetchWithTimeout(url, timeout) {
  const fetchPromise = fetch(url);
  
  const timeoutPromise = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('请求超时');
    }, timeout);
  });
  
  return Promise.race([fetchPromise, timeoutPromise]);
}

// 使用
fetchWithTimeout('/api/data', 3000)
  .then(data => console.log('请求成功', data))
  .catch(error => console.error('请求失败或超时', error));

实用案例:多个资源竞速

// 从多个镜像服务器请求,使用最快响应的那个
const mirrors = [
  'https://mirror1.com/data',
  'https://mirror2.com/data',
  'https://mirror3.com/data'
];

Promise.race(mirrors.map(url => fetch(url)))
  .then(response => response.json())
  .then(data => console.log('最快的服务器返回:', data))
  .catch(error => console.error('所有服务器都失败了', error));

5.5 Promise.allSettled()

用途:等待所有 Promise 都完成(无论成功还是失败),返回所有结果。

// 语法(ES2020)
Promise.allSettled([promise1, promise2, promise3])

特点

  • ✅ 永远不会 reject
  • ✅ 返回每个 Promise 的状态和结果
  • ✅ 适合需要知道所有结果的场景
// 示例
const promises = [
  Promise.resolve('成功1'),
  Promise.reject('失败2'),
  Promise.resolve('成功3')
];

Promise.allSettled(promises)
  .then(results => {
    console.log(results);
    /* 输出:
    [
      { status: 'fulfilled', value: '成功1' },
      { status: 'rejected', reason: '失败2' },
      { status: 'fulfilled', value: '成功3' }
    ]
    */
    
    // 可以分别处理成功和失败的情况
    results.forEach(result => {
      if (result.status === 'fulfilled') {
        console.log('成功:', result.value);
      } else {
        console.log('失败:', result.reason);
      }
    });
  });

实用案例:批量操作统计

async function batchDeleteUsers(userIds) {
  const deletePromises = userIds.map(id => 
    fetch(`/api/users/${id}`, { method: 'DELETE' })
  );
  
  const results = await Promise.allSettled(deletePromises);
  
  const success = results.filter(r => r.status === 'fulfilled').length;
  const failed = results.filter(r => r.status === 'rejected').length;
  
  console.log(`删除完成:成功 ${success} 个,失败 ${failed}`);
  
  return results;
}

5.6 Promise.any()

用途:只要有一个 Promise 成功就返回,所有 Promise 都失败才失败。

// 语法(ES2021)
Promise.any([promise1, promise2, promise3])

特点

  • ✅ 返回第一个成功的 Promise 结果
  • ❌ 所有 Promise 都失败,返回 AggregateError
// 示例
const promises = [
  Promise.reject('失败1'),
  Promise.resolve('成功2'),
  Promise.resolve('成功3')
];

Promise.any(promises)
  .then(value => {
    console.log(value); // 成功2(第一个成功的)
  })
  .catch(error => {
    console.error('所有 Promise 都失败了', error);
  });

实用案例:容错请求

// 尝试从多个备用服务器获取数据
function fetchFromBackup(endpoints) {
  const promises = endpoints.map(url => fetch(url));
  
  return Promise.any(promises)
    .then(response => response.json())
    .catch(error => {
      throw new Error('所有服务器都不可用');
    });
}

// 使用
fetchFromBackup([
  'https://primary.com/api',
  'https://backup1.com/api',
  'https://backup2.com/api'
])
.then(data => console.log('成功获取数据:', data))
.catch(error => console.error(error));

5.7 静态方法对比表

方法 用途 成功条件 失败条件 返回值
Promise.all() 全部成功 所有成功 任一失败 所有结果数组
Promise.race() 竞速 最先完成的 最先完成的 第一个完成的结果
Promise.allSettled() 等待全部完成 全部完成 不会失败 所有结果状态数组
Promise.any() 任一成功 任一成功 全部失败 第一个成功的结果

6. Promise 链式调用深度解析

6.1 链式调用的原理

核心原理:每个 then() 方法都返回一个新的 Promise

// 链式调用示例
const promise = new Promise(resolve => {
  resolve(1);
});

const promise2 = promise.then(value => {
  console.log(value); // 1
  return value + 1;
});

const promise3 = promise2.then(value => {
  console.log(value); // 2
  return value + 1;
});

const promise4 = promise3.then(value => {
  console.log(value); // 3
});

// promise !== promise2 !== promise3 !== promise4
// 每个 then() 都返回新的 Promise

6.2 值的传递规则

// 规则1:返回普通值,传递给下一个 then
Promise.resolve(1)
  .then(value => value + 1)  // 返回 2
  .then(value => value * 2)  // 接收 2,返回 4
  .then(value => {
    console.log(value); // 4
  });

// 规则2:返回 Promise,等待该 Promise 完成
Promise.resolve(1)
  .then(value => {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve(value + 1);
      }, 1000);
    });
  })
  .then(value => {
    console.log(value); // 1秒后输出 2
  });

// 规则3:不返回值,传递 undefined
Promise.resolve(1)
  .then(value => {
    console.log(value); // 1
    // 没有 return
  })
  .then(value => {
    console.log(value); // undefined
  });

// 规则4:抛出错误,传递给 catch
Promise.resolve(1)
  .then(value => {
    throw new Error('出错了');
  })
  .then(value => {
    console.log('不会执行');
  })
  .catch(error => {
    console.error(error.message); // 出错了
  });

6.3 链式调用的实际应用

场景1:多步骤数据处理

// 获取用户信息 → 获取订单 → 获取订单详情 → 处理数据
function getUserOrderDetail(userId) {
  return fetchUser(userId)
    .then(user => {
      console.log('1. 获取用户:', user.name);
      return fetchOrders(user.id);
    })
    .then(orders => {
      console.log('2. 获取订单列表:', orders.length, '条');
      return fetchOrderDetail(orders[0].id);
    })
    .then(detail => {
      console.log('3. 获取订单详情:', detail);
      return {
        orderId: detail.id,
        total: detail.price * detail.quantity
      };
    })
    .then(result => {
      console.log('4. 最终结果:', result);
      return result;
    })
    .catch(error => {
      console.error('任何步骤出错都会被捕获:', error);
    });
}

场景2:条件分支

function processOrder(orderId) {
  return fetchOrder(orderId)
    .then(order => {
      if (order.status === 'paid') {
        // 已支付,发货
        return shipOrder(order.id);
      } else {
        // 未支付,发送提醒
        return sendPaymentReminder(order.id);
      }
    })
    .then(result => {
      console.log('处理完成:', result);
    })
    .catch(error => {
      console.error('处理失败:', error);
    });
}

6.4 链式调用的中断

// 如何在中途中断 Promise 链?
function processData(data) {
  return validateData(data)
    .then(validData => {
      if (!validData.isValid) {
        // 返回一个 rejected Promise 来中断链条
        return Promise.reject('数据验证失败');
      }
      return saveData(validData);
    })
    .then(savedData => {
      console.log('数据保存成功');
      return notifyUser(savedData);
    })
    .catch(error => {
      console.error('中断原因:', error);
    });
}

7. Promise 的错误处理机制

7.1 错误的产生方式

Promise 中的错误有两种产生方式:

// 方式1:调用 reject()
const promise1 = new Promise((resolve, reject) => {
  reject('主动拒绝');
});

// 方式2:抛出异常
const promise2 = new Promise((resolve, reject) => {
  throw new Error('抛出错误');
});

// 这两种方式效果相同
promise1.catch(error => console.log(error)); // 主动拒绝
promise2.catch(error => console.log(error.message)); // 抛出错误

7.2 错误的捕获方式

// 方式1:then 的第二个参数
promise.then(
  value => console.log(value),
  error => console.error('方式1捕获:', error)
);

// 方式2:catch 方法(推荐)
promise
  .then(value => console.log(value))
  .catch(error => console.error('方式2捕获:', error));

两种方式的区别

// 区别:catch 可以捕获 then 中的错误
promise
  .then(value => {
    throw new Error('then 中的错误');
  }, error => {
    // 无法捕获 then 回调中的错误
    console.error('捕获不到');
  });

promise
  .then(value => {
    throw new Error('then 中的错误');
  })
  .catch(error => {
    // 可以捕获 then 回调中的错误
    console.error('可以捕获到:', error.message);
  });

7.3 错误的传播机制

// 错误会一直传播,直到被 catch 捕获
Promise.resolve()
  .then(() => {
    throw new Error('第1步出错');
  })
  .then(() => {
    console.log('第2步:不会执行');
  })
  .then(() => {
    console.log('第3步:不会执行');
  })
  .catch(error => {
    console.error('捕获到错误:', error.message);
    // 错误被处理,链条可以继续
    return '错误已修复';
  })
  .then(value => {
    console.log('第4步:继续执行', value);
  });

7.4 错误恢复机制

// catch 后返回值,链条可以恢复正常流程
function fetchWithRetry(url, retries = 3) {
  return fetch(url)
    .catch(error => {
      if (retries > 0) {
        console.log(`请求失败,剩余重试次数:${retries}`);
        // 返回新的 Promise,继续重试
        return fetchWithRetry(url, retries - 1);
      }
      // 重试次数用完,抛出错误
      throw error;
    });
}

7.5 未捕获的错误

// ⚠️ 如果错误没有被捕获,会产生 UnhandledPromiseRejection
const promise = new Promise((resolve, reject) => {
  reject('未处理的错误');
});

// 浏览器会报警告:Uncaught (in promise) 未处理的错误
// Node.js 会发出 unhandledRejection 事件

// 全局捕获未处理的 Promise 错误(浏览器)
window.addEventListener('unhandledrejection', event => {
  console.error('未处理的 Promise 错误:', event.reason);
  event.preventDefault(); // 阻止默认行为
});

// 全局捕获未处理的 Promise 错误(Node.js)
process.on('unhandledRejection', (reason, promise) => {
  console.error('未处理的 Promise 错误:', reason);
});

7.6 错误处理最佳实践

// ✅ 推荐:总是在 Promise 链的末尾添加 catch
fetchData()
  .then(processData)
  .then(saveData)
  .catch(error => {
    // 统一错误处理
    console.error('操作失败:', error);
    // 可以根据错误类型做不同处理
    if (error.name === 'NetworkError') {
      showErrorMessage('网络错误,请检查网络连接');
    } else if (error.name === 'ValidationError') {
      showErrorMessage('数据验证失败');
    } else {
      showErrorMessage('未知错误');
    }
  })
  .finally(() => {
    // 清理工作
    hideLoading();
  });

// ❌ 不推荐:忘记添加 catch
fetchData()
  .then(processData)
  .then(saveData); // 可能产生未捕获的错误

8. Promise 与事件循环(微任务机制)

8.1 事件循环基础

JavaScript 是单线程语言,通过**事件循环(Event Loop)**来处理异步任务。

事件循环的执行顺序

  1. 执行同步代码(宏任务)
  2. 清空微任务队列
  3. 执行下一个宏任务
  4. 重复步骤 2-3
┌─────────────────────────────┐
│      执行同步代码(宏任务)     │
└──────────────┬──────────────┘
               │
               ↓
┌─────────────────────────────┐
│      清空所有微任务队列        │ ← Promise.then/catch/finally
└──────────────┬──────────────┘
               │
               ↓
┌─────────────────────────────┐
│      执行下一个宏任务          │ ← setTimeout/setInterval
└──────────────┬──────────────┘
               │
               ↓ (循环)

8.2 宏任务 vs 微任务

宏任务(Macro Task)

  • script 整体代码
  • setTimeout
  • setInterval
  • setImmediate(Node.js)
  • I/O 操作
  • UI 渲染

微任务(Micro Task)

  • Promise.then/catch/finally
  • MutationObserver
  • process.nextTick(Node.js)
  • queueMicrotask

重要规则

  • ✅ 微任务优先级高于宏任务
  • ✅ 每执行完一个宏任务,会清空所有微任务
  • ✅ Promise 的回调是微任务

8.3 Promise 的执行时机

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

setTimeout(() => {
  console.log('2. setTimeout 宏任务');
}, 0);

Promise.resolve()
  .then(() => {
    console.log('3. Promise.then 微任务');
  });

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

// 输出顺序:
// 1. 同步代码开始
// 4. 同步代码结束
// 3. Promise.then 微任务
// 2. setTimeout 宏任务

执行过程分析

  1. 执行同步代码:输出 1、4
  2. 同步代码执行完毕,检查微任务队列
  3. 执行微任务:输出 3
  4. 微任务清空,执行宏任务:输出 2

8.4 复杂示例分析

console.log('script start');

setTimeout(() => {
  console.log('setTimeout');
}, 0);

Promise.resolve()
  .then(() => {
    console.log('promise1');
  })
  .then(() => {
    console.log('promise2');
  });

new Promise((resolve) => {
  console.log('promise3');
  resolve();
})
  .then(() => {
    console.log('promise4');
  });

console.log('script end');

// 输出顺序:
// script start
// promise3       ← new Promise 的执行器是同步的
// script end
// promise1       ← 第一批微任务
// promise4       ← 第一批微任务
// promise2       ← 第二批微任务(promise1 的 then)
// setTimeout     ← 宏任务

8.5 Promise 构造函数是同步的

console.log('1');

const promise = new Promise((resolve) => {
  console.log('2'); // ← 立即执行
  resolve();
  console.log('3'); // ← 立即执行
});

promise.then(() => {
  console.log('4'); // ← 微任务
});

console.log('5');

// 输出顺序:1 → 2 → 3 → 5 → 4

关键点

  • new Promise(executor) 中的 executor 函数是同步执行
  • ✅ 只有 then/catch/finally 的回调是微任务

8.6 实战:微任务与宏任务混合

console.log('1');

setTimeout(() => {
  console.log('2');
  Promise.resolve().then(() => {
    console.log('3');
  });
}, 0);

new Promise((resolve) => {
  console.log('4');
  resolve();
  setTimeout(() => {
    console.log('5');
  }, 0);
})
  .then(() => {
    console.log('6');
    setTimeout(() => {
      console.log('7');
    }, 0);
  });

console.log('8');

// 输出顺序:1 → 4 → 8 → 6 → 2 → 3 → 5 → 7

分析过程

  1. 同步代码:1、4、8
  2. 微任务队列:6
  3. 宏任务队列:setTimeout(2)、setTimeout(5)
  4. 执行微任务:6(同时添加 setTimeout(7))
  5. 执行宏任务:2(添加微任务 3)
  6. 清空微任务:3
  7. 执行宏任务:5、7

9. async/await:Promise 的语法糖

9.1 async/await 基础

async/await 是 ES2017 引入的语法,让异步代码看起来像同步代码。

// Promise 写法
function fetchUser() {
  return fetch('/api/user')
    .then(response => response.json())
    .then(user => {
      console.log(user);
      return user;
    })
    .catch(error => {
      console.error(error);
    });
}

// async/await 写法
async function fetchUser() {
  try {
    const response = await fetch('/api/user');
    const user = await response.json();
    console.log(user);
    return user;
  } catch (error) {
    console.error(error);
  }
}

9.2 async 函数

async 关键字

  • async 函数总是返回一个 Promise
  • ✅ 函数内的返回值会被自动包装成 Promise
// 示例1:返回普通值
async function getValue() {
  return 'hello';
}

getValue().then(value => {
  console.log(value); // hello
});

// 等价于
function getValue() {
  return Promise.resolve('hello');
}

// 示例2:返回 Promise
async function getPromise() {
  return Promise.resolve('world');
}

getPromise().then(value => {
  console.log(value); // world
});

// 示例3:抛出错误
async function throwError() {
  throw new Error('出错了');
}

throwError().catch(error => {
  console.error(error.message); // 出错了
});

9.3 await 关键字

await 关键字

  • ✅ 只能在 async 函数中使用
  • ✅ 等待 Promise 完成,返回 fulfilled 的值
  • ✅ 如果 Promise rejected,抛出错误
// 示例:await 的使用
async function example() {
  // 等待 Promise 完成
  const value1 = await Promise.resolve('成功');
  console.log(value1); // 成功
  
  // await 也可以用于非 Promise 值
  const value2 = await 'hello';
  console.log(value2); // hello(立即返回)
  
  // await 后面的代码会等待 Promise 完成后执行
  const value3 = await new Promise(resolve => {
    setTimeout(() => resolve('延迟1秒'), 1000);
  });
  console.log(value3); // 1秒后输出:延迟1秒
}

9.4 错误处理

// 方式1:try-catch(推荐)
async function fetchData() {
  try {
    const response = await fetch('/api/data');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('请求失败:', error);
    // 可以选择重新抛出或返回默认值
    return null;
  }
}

// 方式2:catch 方法
async function fetchData() {
  const response = await fetch('/api/data').catch(error => {
    console.error('请求失败:', error);
    return null;
  });
  
  if (!response) return null;
  
  const data = await response.json();
  return data;
}

// 方式3:统一错误处理
async function fetchData() {
  const response = await fetch('/api/data');
  const data = await response.json();
  return data;
}

// 调用时处理错误
fetchData()
  .then(data => console.log(data))
  .catch(error => console.error(error));

9.5 并发执行

// ❌ 串行执行(慢)
async function sequential() {
  const user = await fetchUser();     // 等待1秒
  const orders = await fetchOrders(); // 再等待1秒
  const products = await fetchProducts(); // 再等待1秒
  // 总共需要3秒
  return { user, orders, products };
}

// ✅ 并发执行(快)
async function concurrent() {
  // 同时发起请求
  const [user, orders, products] = await Promise.all([
    fetchUser(),
    fetchOrders(),
    fetchProducts()
  ]);
  // 总共只需要1秒(最慢的那个请求的时间)
  return { user, orders, products };
}

// ✅ 更灵活的并发控制
async function flexible() {
  // 先发起所有请求
  const userPromise = fetchUser();
  const ordersPromise = fetchOrders();
  const productsPromise = fetchProducts();
  
  // 按需等待
  const user = await userPromise;
  console.log('用户信息已获取:', user);
  
  const orders = await ordersPromise;
  console.log('订单信息已获取:', orders);
  
  const products = await productsPromise;
  console.log('商品信息已获取:', products);
  
  return { user, orders, products };
}

9.6 循环中使用 await

// ❌ 在 forEach 中使用 await(不会等待)
async function processItems() {
  const items = [1, 2, 3];
  
  items.forEach(async (item) => {
    await processItem(item);
    console.log('处理完成:', item);
  });
  
  console.log('全部完成'); // 这行会先执行!
}

// ✅ 使用 for...of(串行)
async function processItemsSerial() {
  const items = [1, 2, 3];
  
  for (const item of items) {
    await processItem(item);
    console.log('处理完成:', item);
  }
  
  console.log('全部完成'); // 确保所有处理完成后执行
}

// ✅ 使用 Promise.all(并行)
async function processItemsParallel() {
  const items = [1, 2, 3];
  
  await Promise.all(items.map(item => processItem(item)));
  
  console.log('全部完成');
}

// ✅ 使用 for 循环(串行,更灵活)
async function processItemsFlexible() {
  const items = [1, 2, 3];
  const results = [];
  
  for (let i = 0; i < items.length; i++) {
    const result = await processItem(items[i]);
    results.push(result);
    console.log(`进度:${i + 1}/${items.length}`);
  }
  
  console.log('全部完成', results);
  return results;
}

9.7 async/await 与 Promise 对比

// Promise 链式调用
function getUserOrders() {
  return fetchUser()
    .then(user => fetchOrders(user.id))
    .then(orders => {
      return orders.filter(order => order.status === 'paid');
    })
    .catch(error => {
      console.error(error);
      throw error;
    });
}

// async/await 版本
async function getUserOrders() {
  try {
    const user = await fetchUser();
    const orders = await fetchOrders(user.id);
    return orders.filter(order => order.status === 'paid');
  } catch (error) {
    console.error(error);
    throw error;
  }
}

优势对比

  • ✅ async/await 更接近同步代码的思维方式
  • ✅ 错误处理使用熟悉的 try-catch
  • ✅ 更容易调试(断点、堆栈跟踪)
  • ✅ 代码更简洁,避免回调嵌套

10. Promise 实战应用场景

10.1 网络请求封装

// 封装一个通用的请求函数
function request(url, options = {}) {
  return fetch(url, {
    method: options.method || 'GET',
    headers: {
      'Content-Type': 'application/json',
      ...options.headers
    },
    body: options.body ? JSON.stringify(options.body) : undefined
  })
    .then(response => {
      // 检查响应状态
      if (!response.ok) {
        throw new Error(`HTTP Error: ${response.status}`);
      }
      return response.json();
    })
    .catch(error => {
      console.error('请求失败:', error);
      throw error;
    });
}

// 使用
request('/api/users')
  .then(users => console.log(users))
  .catch(error => console.error(error));

// 带超时的请求
function requestWithTimeout(url, options = {}, timeout = 5000) {
  return Promise.race([
    request(url, options),
    new Promise((_, reject) => {
      setTimeout(() => reject(new Error('请求超时')), timeout);
    })
  ]);
}

10.2 重试机制

// 实现请求重试
function fetchWithRetry(url, options = {}, maxRetries = 3) {
  return fetch(url, options)
    .catch(error => {
      if (maxRetries <= 0) {
        throw error;
      }
      
      console.log(`请求失败,重试中... (剩余 ${maxRetries} 次)`);
      
      // 延迟后重试
      return new Promise(resolve => {
        setTimeout(() => {
          resolve(fetchWithRetry(url, options, maxRetries - 1));
        }, 1000);
      });
    });
}

// 使用
fetchWithRetry('/api/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('重试失败:', error));

// 更高级的重试:指数退避
async function fetchWithExponentialBackoff(url, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url);
      return await response.json();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      
      const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s...
      console.log(`重试中... ${delay}ms 后重试`);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

10.3 并发控制

// 控制并发数量,避免同时发起过多请求
class PromisePool {
  constructor(maxConcurrent) {
    this.maxConcurrent = maxConcurrent; // 最大并发数
    this.currentCount = 0;              // 当前并发数
    this.queue = [];                    // 等待队列
  }
  
  async add(promiseCreator) {
    // 如果达到最大并发数,等待
    while (this.currentCount >= this.maxConcurrent) {
      await new Promise(resolve => this.queue.push(resolve));
    }
    
    // 执行任务
    this.currentCount++;
    
    try {
      const result = await promiseCreator();
      return result;
    } finally {
      this.currentCount--;
      
      // 从队列中取出下一个任务
      const resolve = this.queue.shift();
      if (resolve) resolve();
    }
  }
}

// 使用示例
async function batchFetch(urls) {
  const pool = new PromisePool(3); // 最多同时3个请求
  
  const promises = urls.map(url => {
    return pool.add(() => fetch(url).then(r => r.json()));
  });
  
  return Promise.all(promises);
}

// 测试
const urls = Array.from({ length: 10 }, (_, i) => `/api/data/${i}`);
batchFetch(urls)
  .then(results => console.log('所有请求完成:', results))
  .catch(error => console.error(error));

10.4 图片预加载

// 预加载单张图片
function preloadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    
    img.onload = () => resolve(img);
    img.onerror = () => reject(new Error(`图片加载失败: ${url}`));
    
    img.src = url;
  });
}

// 批量预加载图片
async function preloadImages(urls) {
  const results = await Promise.allSettled(
    urls.map(url => preloadImage(url))
  );
  
  const success = results.filter(r => r.status === 'fulfilled').length;
  const failed = results.filter(r => r.status === 'rejected').length;
  
  console.log(`图片加载完成:成功 ${success} 张,失败 ${failed}`);
  
  return results
    .filter(r => r.status === 'fulfilled')
    .map(r => r.value);
}

// 使用
const imageUrls = [
  '/images/1.jpg',
  '/images/2.jpg',
  '/images/3.jpg'
];

preloadImages(imageUrls)
  .then(images => {
    console.log('所有图片已加载:', images);
    // 可以开始显示图片
  });

10.5 数据缓存

// 带缓存的数据获取
class DataCache {
  constructor() {
    this.cache = new Map();
    this.pendingPromises = new Map();
  }
  
  async fetch(key, fetcher, ttl = 60000) {
    // 检查缓存
    const cached = this.cache.get(key);
    if (cached && Date.now() - cached.timestamp < ttl) {
      console.log('从缓存获取:', key);
      return cached.data;
    }
    
    // 检查是否有正在进行的请求
    if (this.pendingPromises.has(key)) {
      console.log('等待正在进行的请求:', key);
      return this.pendingPromises.get(key);
    }
    
    // 发起新请求
    console.log('发起新请求:', key);
    const promise = fetcher()
      .then(data => {
        // 存入缓存
        this.cache.set(key, {
          data,
          timestamp: Date.now()
        });
        
        // 移除待处理记录
        this.pendingPromises.delete(key);
        
        return data;
      })
      .catch(error => {
        // 移除待处理记录
        this.pendingPromises.delete(key);
        throw error;
      });
    
    // 记录待处理的 Promise
    this.pendingPromises.set(key, promise);
    
    return promise;
  }
  
  clear(key) {
    if (key) {
      this.cache.delete(key);
    } else {
      this.cache.clear();
    }
  }
}

// 使用
const cache = new DataCache();

function getUser(id) {
  return cache.fetch(
    `user:${id}`,
    () => fetch(`/api/users/${id}`).then(r => r.json()),
    30000 // 30秒缓存
  );
}

// 多次调用,只会发起一次请求
getUser(1).then(user => console.log('第1次:', user));
getUser(1).then(user => console.log('第2次:', user)); // 使用缓存
getUser(1).then(user => console.log('第3次:', user)); // 使用缓存

10.6 顺序执行

// 顺序执行一组异步任务
function sequentialExecute(tasks) {
  return tasks.reduce((promise, task) => {
    return promise.then(results => {
      return task().then(result => {
        return [...results, result];
      });
    });
  }, Promise.resolve([]));
}

// 使用
const tasks = [
  () => fetch('/api/step1').then(r => r.json()),
  () => fetch('/api/step2').then(r => r.json()),
  () => fetch('/api/step3').then(r => r.json())
];

sequentialExecute(tasks)
  .then(results => {
    console.log('所有步骤完成:', results);
  });

// async/await 版本
async function sequentialExecuteAsync(tasks) {
  const results = [];
  
  for (const task of tasks) {
    const result = await task();
    results.push(result);
  }
  
  return results;
}

10.7 轮询

// 定时轮询,直到满足条件
function poll(fn, validate, interval = 1000, maxAttempts = 30) {
  let attempts = 0;
  
  return new Promise((resolve, reject) => {
    const executePoll = async () => {
      try {
        const result = await fn();
        attempts++;
        
        if (validate(result)) {
          resolve(result);
        } else if (attempts >= maxAttempts) {
          reject(new Error('轮询超时'));
        } else {
          setTimeout(executePoll, interval);
        }
      } catch (error) {
        reject(error);
      }
    };
    
    executePoll();
  });
}

// 使用:轮询订单状态
poll(
  () => fetch('/api/order/123').then(r => r.json()),
  order => order.status === 'completed',
  2000, // 每2秒轮询一次
  30    // 最多30次(1分钟)
)
  .then(order => console.log('订单完成:', order))
  .catch(error => console.error('轮询失败:', error));

11. Promise 常见陷阱与最佳实践

11.1 忘记返回 Promise

// ❌ 错误:忘记返回 Promise
function getUserData() {
  fetchUser().then(user => {
    return fetchOrders(user.id); // 返回了,但是外层函数没有返回
  });
}

getUserData().then(data => {
  console.log(data); // undefined
});

// ✅ 正确:返回 Promise
function getUserData() {
  return fetchUser().then(user => {
    return fetchOrders(user.id);
  });
}

getUserData().then(data => {
  console.log(data); // 正确的数据
});

11.2 Promise 嵌套

// ❌ 错误:Promise 嵌套(Promise 地狱)
function getData() {
  return fetchUser().then(user => {
    return fetchOrders(user.id).then(orders => {
      return fetchProducts(orders[0].id).then(products => {
        return products;
      });
    });
  });
}

// ✅ 正确:链式调用
function getData() {
  return fetchUser()
    .then(user => fetchOrders(user.id))
    .then(orders => fetchProducts(orders[0].id))
    .then(products => products);
}

// ✅ 更好:async/await
async function getData() {
  const user = await fetchUser();
  const orders = await fetchOrders(user.id);
  const products = await fetchProducts(orders[0].id);
  return products;
}

11.3 忘记错误处理

// ❌ 错误:没有错误处理
fetchUser()
  .then(user => console.log(user)); // 如果出错,会产生未捕获的错误

// ✅ 正确:添加 catch
fetchUser()
  .then(user => console.log(user))
  .catch(error => console.error(error));

// ✅ 或者在调用时处理
async function main() {
  try {
    const user = await fetchUser();
    console.log(user);
  } catch (error) {
    console.error(error);
  }
}

11.4 在循环中创建 Promise

// ❌ 错误:在循环中使用 async/await(串行执行)
async function processUsers(userIds) {
  const results = [];
  
  for (const id of userIds) {
    const user = await fetchUser(id); // 逐个等待
    results.push(user);
  }
  
  return results; // 如果有10个用户,每个1秒,总共10秒
}

// ✅ 正确:并行执行
async function processUsers(userIds) {
  return Promise.all(userIds.map(id => fetchUser(id)));
  // 总共只需要1秒
}

// ✅ 如果需要控制并发数
async function processUsers(userIds) {
  const pool = new PromisePool(3);
  return Promise.all(
    userIds.map(id => pool.add(() => fetchUser(id)))
  );
}

11.5 Promise 构造函数反模式

// ❌ 错误:不必要的 Promise 包装
function getUser() {
  return new Promise((resolve, reject) => {
    fetchUser() // fetchUser 已经返回 Promise
      .then(user => resolve(user))
      .catch(error => reject(error));
  });
}

// ✅ 正确:直接返回 Promise
function getUser() {
  return fetchUser();
}

// ❌ 错误:包装 async 函数
function getUser() {
  return new Promise(async (resolve, reject) => {
    try {
      const user = await fetchUser();
      resolve(user);
    } catch (error) {
      reject(error);
    }
  });
}

// ✅ 正确:直接使用 async 函数
async function getUser() {
  return await fetchUser();
}

11.6 then() 中的副作用

// ❌ 不好:在 then 中修改外部变量
let userData;

fetchUser()
  .then(user => {
    userData = user; // 副作用
  });

console.log(userData); // undefined(异步还没完成)

// ✅ 好:使用返回值
fetchUser()
  .then(user => {
    console.log(user); // 在这里使用数据
    return user;
  });

// ✅ 或者使用 async/await
async function main() {
  const userData = await fetchUser();
  console.log(userData); // 确保数据已获取
}

11.7 最佳实践总结

// ✅ 1. 总是返回 Promise
function getData() {
  return fetchData(); // 返回 Promise
}

// ✅ 2. 使用链式调用,避免嵌套
getData()
  .then(processData)
  .then(saveData)
  .catch(handleError);

// ✅ 3. 总是添加错误处理
promise
  .then(handleSuccess)
  .catch(handleError)
  .finally(cleanup);

// ✅ 4. 优先使用 async/await
async function main() {
  try {
    const data = await fetchData();
    const processed = await processData(data);
    return processed;
  } catch (error) {
    handleError(error);
  } finally {
    cleanup();
  }
}

// ✅ 5. 并行执行独立的异步操作
async function loadData() {
  const [users, orders, products] = await Promise.all([
    fetchUsers(),
    fetchOrders(),
    fetchProducts()
  ]);
  
  return { users, orders, products };
}

// ✅ 6. 使用有意义的变量名
// 不好
promise.then(d => console.log(d));

// 好
promise.then(userData => console.log(userData));

// ✅ 7. 避免过长的 Promise 链
// 不好
fetch()
  .then(r => r.json())
  .then(d => process(d))
  .then(pd => transform(pd))
  .then(td => validate(td))
  .then(vd => save(vd))
  .then(sd => notify(sd));

// 好:拆分成多个函数
async function processData() {
  const response = await fetch();
  const data = await response.json();
  const processed = await process(data);
  const transformed = await transform(processed);
  const validated = await validate(transformed);
  const saved = await save(validated);
  return notify(saved);
}

12. 手写 Promise(深入理解原理)

12.1 Promise/A+ 规范核心要点

Promise/A+ 是 Promise 的标准规范,核心要求:

  1. Promise 有三个状态:pending、fulfilled、rejected
  2. 状态只能从 pending 变为 fulfilled 或 rejected
  3. 状态一旦改变,不能再变
  4. then 方法返回新的 Promise
  5. then 方法可以链式调用

12.2 简易版 Promise 实现

// 简易版 Promise 实现(教学用)
class MyPromise {
  // 三个状态常量
  static PENDING = 'pending';
  static FULFILLED = 'fulfilled';
  static REJECTED = 'rejected';
  
  constructor(executor) {
    // 初始状态
    this.state = MyPromise.PENDING;
    // 成功的值
    this.value = undefined;
    // 失败的原因
    this.reason = undefined;
    // 成功回调队列
    this.onFulfilledCallbacks = [];
    // 失败回调队列
    this.onRejectedCallbacks = [];
    
    // resolve 函数
    const resolve = (value) => {
      // 只有 pending 状态才能转换
      if (this.state === MyPromise.PENDING) {
        this.state = MyPromise.FULFILLED;
        this.value = value;
        // 执行所有成功回调
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };
    
    // reject 函数
    const reject = (reason) => {
      // 只有 pending 状态才能转换
      if (this.state === MyPromise.PENDING) {
        this.state = MyPromise.REJECTED;
        this.reason = reason;
        // 执行所有失败回调
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };
    
    try {
      // 立即执行 executor
      executor(resolve, reject);
    } catch (error) {
      // 如果执行器抛出错误,直接 reject
      reject(error);
    }
  }
  
  // then 方法
  then(onFulfilled, onRejected) {
    // 参数默认值
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
    
    // 返回新的 Promise
    const promise2 = new MyPromise((resolve, reject) => {
      // 如果已经是 fulfilled 状态
      if (this.state === MyPromise.FULFILLED) {
        // 使用 setTimeout 模拟微任务
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolve(x);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }
      
      // 如果已经是 rejected 状态
      if (this.state === MyPromise.REJECTED) {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolve(x);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }
      
      // 如果还是 pending 状态,保存回调
      if (this.state === MyPromise.PENDING) {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolve(x);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
        
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolve(x);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });
    
    return promise2;
  }
  
  // catch 方法
  catch(onRejected) {
    return this.then(null, onRejected);
  }
  
  // finally 方法
  finally(onFinally) {
    return this.then(
      value => {
        onFinally();
        return value;
      },
      reason => {
        onFinally();
        throw reason;
      }
    );
  }
  
  // 静态方法:resolve
  static resolve(value) {
    if (value instanceof MyPromise) {
      return value;
    }
    
    return new MyPromise(resolve => {
      resolve(value);
    });
  }
  
  // 静态方法:reject
  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason);
    });
  }
  
  // 静态方法:all
  static all(promises) {
    return new MyPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        reject(new TypeError('参数必须是数组'));
        return;
      }
      
      const results = [];
      let count = 0;
      
      if (promises.length === 0) {
        resolve(results);
        return;
      }
      
      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          value => {
            results[index] = value;
            count++;
            
            if (count === promises.length) {
              resolve(results);
            }
          },
          reason => {
            reject(reason);
          }
        );
      });
    });
  }
  
  // 静态方法:race
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        reject(new TypeError('参数必须是数组'));
        return;
      }
      
      promises.forEach(promise => {
        MyPromise.resolve(promise).then(resolve, reject);
      });
    });
  }
}

12.3 测试手写的 Promise

// 测试1:基本功能
console.log('=== 测试1:基本功能 ===');
const promise1 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功');
  }, 1000);
});

promise1.then(value => {
  console.log('1. Promise resolved:', value);
});

// 测试2:链式调用
console.log('=== 测试2:链式调用 ===');
MyPromise.resolve(1)
  .then(value => {
    console.log('2. 第1步:', value);
    return value + 1;
  })
  .then(value => {
    console.log('2. 第2步:', value);
    return value + 1;
  })
  .then(value => {
    console.log('2. 第3步:', value);
  });

// 测试3:错误处理
console.log('=== 测试3:错误处理 ===');
MyPromise.reject('错误')
  .then(value => {
    console.log('不会执行');
  })
  .catch(reason => {
    console.log('3. 捕获错误:', reason);
  });

// 测试4:Promise.all
console.log('=== 测试4:Promise.all ===');
MyPromise.all([
  MyPromise.resolve(1),
  MyPromise.resolve(2),
  MyPromise.resolve(3)
])
  .then(values => {
    console.log('4. Promise.all:', values);
  });

// 测试5:Promise.race
console.log('=== 测试5:Promise.race ===');
MyPromise.race([
  new MyPromise(resolve => setTimeout(() => resolve('慢'), 2000)),
  new MyPromise(resolve => setTimeout(() => resolve('快'), 1000))
])
  .then(value => {
    console.log('5. Promise.race:', value);
  });

12.4 完整版 Promise(处理 Promise 链式返回)

// 完整版需要处理 then 返回 Promise 的情况
class MyPromiseComplete extends MyPromise {
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
    
    const promise2 = new MyPromiseComplete((resolve, reject) => {
      const handleFulfilled = () => {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            // 处理返回值
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      };
      
      const handleRejected = () => {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            // 处理返回值
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      };
      
      if (this.state === MyPromise.FULFILLED) {
        handleFulfilled();
      } else if (this.state === MyPromise.REJECTED) {
        handleRejected();
      } else {
        this.onFulfilledCallbacks.push(handleFulfilled);
        this.onRejectedCallbacks.push(handleRejected);
      }
    });
    
    return promise2;
  }
  
  // 处理 Promise 解析
  resolvePromise(promise2, x, resolve, reject) {
    // 避免循环引用
    if (promise2 === x) {
      reject(new TypeError('循环引用'));
      return;
    }
    
    // 如果 x 是 Promise
    if (x instanceof MyPromiseComplete) {
      x.then(resolve, reject);
      return;
    }
    
    // 如果 x 是对象或函数
    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
      try {
        const then = x.then;
        
        if (typeof then === 'function') {
          // 如果 x 有 then 方法,当作 Promise 处理
          then.call(x, resolve, reject);
        } else {
          resolve(x);
        }
      } catch (error) {
        reject(error);
      }
    } else {
      // 普通值
      resolve(x);
    }
  }
}

// 测试循环引用
const p = new MyPromiseComplete(resolve => {
  resolve(1);
});

const p2 = p.then(() => {
  return p2; // 循环引用
});

p2.catch(error => {
  console.log('循环引用错误:', error.message);
});

13. 总结与知识图谱

13.1 Promise 核心知识点

Promise 核心体系
│
├─ 基础概念
│  ├─ 三种状态(pending、fulfilled、rejected)
│  ├─ 状态不可逆
│  └─ 解决回调地狱
│
├─ 核心方法
│  ├─ then()   - 链式调用核心
│  ├─ catch()  - 错误处理
│  └─ finally()- 清理操作
│
├─ 静态方法
│  ├─ Promise.resolve()    - 快速创建成功 Promise
│  ├─ Promise.reject()     - 快速创建失败 Promise
│  ├─ Promise.all()        - 全部成功才成功
│  ├─ Promise.race()       - 竞速,返回最快的
│  ├─ Promise.allSettled() - 等待全部完成
│  └─ Promise.any()        - 任一成功即成功
│
├─ 执行机制
│  ├─ 微任务队列
│  ├─ 事件循环
│  └─ 与宏任务的关系
│
├─ 语法糖
│  ├─ async 函数
│  └─ await 关键字
│
└─ 实战应用
   ├─ 网络请求封装
   ├─ 重试机制
   ├─ 并发控制
   ├─ 超时处理
   └─ 错误处理

13.2 Promise 状态转换图

初始状态
   ↓
pending(进行中)
   ├─ resolve() ─→ fulfilled(已成功)─┐
   │                                    │
   └─ reject()  ─→ rejected(已失败) ─┤
                                        │
                                        ↓
                                   状态凝固
                                   永不改变

13.3 Promise 方法对比

特性 then catch finally
处理成功
处理失败
接收参数
返回 Promise
改变 Promise 值

13.4 Promise 静态方法对比

方法 输入 成功条件 失败条件 返回值
all Promise[] 全部成功 任一失败 结果数组
race Promise[] 最先完成 最先完成 首个结果
allSettled Promise[] 全部完成 不会失败 状态数组
any Promise[] 任一成功 全部失败 首个成功

13.5 最佳实践检查清单

✅ 代码规范

  • 总是返回 Promise
  • 使用链式调用,避免嵌套
  • 优先使用 async/await
  • 使用有意义的变量名

✅ 错误处理

  • 每个 Promise 链都有 catch
  • 使用 try-catch 包裹 await
  • 处理未捕获的 Promise 错误
  • 记录错误日志

✅ 性能优化

  • 并行执行独立的异步操作
  • 控制并发数量
  • 使用缓存减少重复请求
  • 实现请求去重

✅ 代码维护

  • 拆分过长的 Promise 链
  • 提取可复用的 Promise 函数
  • 添加适当的注释
  • 编写单元测试

13.6 学习路径建议

第1阶段:基础入门(1-2天)
├─ 理解 Promise 的概念和意义
├─ 掌握三种状态
├─ 学会创建和使用 Promise
└─ 练习 then/catch/finally

第2阶段:深入理解(3-5天)
├─ 理解链式调用原理
├─ 掌握错误处理机制
├─ 学习静态方法
└─ 理解微任务机制

第3阶段:实战应用(1周)
├─ 封装网络请求
├─ 实现重试机制
├─ 处理并发控制
└─ 结合 async/await

第4阶段:高级进阶(1周)
├─ 手写 Promise
├─ 深入事件循环
├─ 性能优化
└─ 阅读源码

13.7 常见问题 FAQ

Q1: Promise 和 async/await 有什么区别?

  • async/await 是 Promise 的语法糖
  • async 函数返回 Promise
  • await 等待 Promise 完成
  • async/await 代码更像同步代码,更易读

Q2: 什么时候用 Promise.all,什么时候用 Promise.race?

  • Promise.all:需要等待所有结果(如批量请求)
  • Promise.race:需要最快的结果(如超时控制)

Q3: 如何取消一个 Promise?

  • Promise 本身不支持取消
  • 可以使用 AbortController(Fetch API)
  • 或者自己实现取消逻辑(包装 Promise)

Q4: Promise 的错误为什么没有被捕获?

  • 检查是否添加了 catch
  • 检查 catch 的位置(是否在错误发生之后)
  • 检查是否使用了 return

Q5: 为什么 Promise 的回调不会立即执行?

  • Promise 的回调是微任务
  • 微任务在当前宏任务完成后执行
  • 这是事件循环的机制

13.8 推荐学习资源

文档

实践

  • 在项目中使用 Promise 替代回调
  • 尝试手写 Promise
  • 阅读优秀开源库的 Promise 使用
  • 做 LeetCode 相关题目

🎯 结语

Promise 是现代 JavaScript 异步编程的基石,掌握 Promise 对于前端开发至关重要。

学习建议

  1. 先理解概念,再动手实践
  2. 多写代码,遇到问题多思考
  3. 阅读优秀的开源代码
  4. 尝试手写 Promise 加深理解

记住这三个核心

  • 🎯 Promise 是一个状态机(三种状态,不可逆)
  • 🎯 then 返回新 Promise(支持链式调用)
  • 🎯 错误会向下传播(直到被 catch)

希望这篇文章能帮助你全面掌握 Promise!加油!💪

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐