logo

手写Promise核心实现与静态方法解析:all与race的深度实践

作者:新兰2025.09.19 12:47浏览量:1

简介:本文通过手写Promise类及静态方法all/race,深度解析异步编程核心机制,结合代码示例与场景分析,帮助开发者掌握Promise底层原理并提升实战能力。

一、Promise核心机制解析

1.1 Promise基础规范

Promise是ES6引入的异步解决方案,遵循Promises/A+规范,包含三种状态:

  • Pending(初始态)
  • Fulfilled(成功态)
  • Rejected(失败态)

状态转换具有不可逆性,一旦从Pending转为Fulfilled/Rejected,将永久保持该状态。

1.2 手写Promise类实现

  1. class MyPromise {
  2. constructor(executor) {
  3. this.state = 'pending'; // 初始状态
  4. this.value = undefined; // 成功值
  5. this.reason = undefined; // 失败原因
  6. this.onFulfilledCallbacks = []; // 成功回调队列
  7. this.onRejectedCallbacks = []; // 失败回调队列
  8. const resolve = (value) => {
  9. if (this.state === 'pending') {
  10. this.state = 'fulfilled';
  11. this.value = value;
  12. this.onFulfilledCallbacks.forEach(fn => fn());
  13. }
  14. };
  15. const reject = (reason) => {
  16. if (this.state === 'pending') {
  17. this.state = 'rejected';
  18. this.reason = reason;
  19. this.onRejectedCallbacks.forEach(fn => fn());
  20. }
  21. };
  22. try {
  23. executor(resolve, reject);
  24. } catch (err) {
  25. reject(err);
  26. }
  27. }
  28. then(onFulfilled, onRejected) {
  29. // 参数可选处理
  30. onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
  31. onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
  32. const promise2 = new MyPromise((resolve, reject) => {
  33. if (this.state === 'fulfilled') {
  34. setTimeout(() => {
  35. try {
  36. const x = onFulfilled(this.value);
  37. resolvePromise(promise2, x, resolve, reject);
  38. } catch (e) {
  39. reject(e);
  40. }
  41. }, 0);
  42. } else if (this.state === 'rejected') {
  43. setTimeout(() => {
  44. try {
  45. const x = onRejected(this.reason);
  46. resolvePromise(promise2, x, resolve, reject);
  47. } catch (e) {
  48. reject(e);
  49. }
  50. }, 0);
  51. } else if (this.state === 'pending') {
  52. this.onFulfilledCallbacks.push(() => {
  53. setTimeout(() => {
  54. try {
  55. const x = onFulfilled(this.value);
  56. resolvePromise(promise2, x, resolve, reject);
  57. } catch (e) {
  58. reject(e);
  59. }
  60. }, 0);
  61. });
  62. this.onRejectedCallbacks.push(() => {
  63. setTimeout(() => {
  64. try {
  65. const x = onRejected(this.reason);
  66. resolvePromise(promise2, x, resolve, reject);
  67. } catch (e) {
  68. reject(e);
  69. }
  70. }, 0);
  71. });
  72. }
  73. });
  74. return promise2;
  75. }
  76. }

关键实现点:

  1. 状态管理:通过闭包保存resolve/reject方法
  2. 异步调度:使用setTimeout确保then方法异步执行
  3. 链式调用:每次then返回新Promise实例
  4. 错误处理:try-catch包裹执行过程

1.3 resolvePromise解析

  1. function resolvePromise(promise2, x, resolve, reject) {
  2. if (promise2 === x) {
  3. return reject(new TypeError('Chaining cycle detected'));
  4. }
  5. let called = false;
  6. if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
  7. try {
  8. const then = x.then;
  9. if (typeof then === 'function') {
  10. then.call(
  11. x,
  12. y => {
  13. if (called) return;
  14. called = true;
  15. resolvePromise(promise2, y, resolve, reject);
  16. },
  17. r => {
  18. if (called) return;
  19. called = true;
  20. reject(r);
  21. }
  22. );
  23. } else {
  24. resolve(x);
  25. }
  26. } catch (e) {
  27. if (called) return;
  28. called = true;
  29. reject(e);
  30. }
  31. } else {
  32. resolve(x);
  33. }
  34. }

该函数处理Promise解析的核心逻辑,包括:

  1. 循环引用检测
  2. thenable对象处理
  3. 状态变更的唯一性保证

二、静态方法实现

2.1 Promise.all实现

  1. MyPromise.all = function(promises) {
  2. return new MyPromise((resolve, reject) => {
  3. const results = [];
  4. let count = 0;
  5. if (promises.length === 0) {
  6. resolve(results);
  7. return;
  8. }
  9. promises.forEach((promise, index) => {
  10. // 处理非Promise值
  11. MyPromise.resolve(promise).then(
  12. value => {
  13. results[index] = value;
  14. count++;
  15. if (count === promises.length) {
  16. resolve(results);
  17. }
  18. },
  19. reason => {
  20. reject(reason);
  21. }
  22. );
  23. });
  24. });
  25. };

关键特性:

  1. 参数校验:自动包装非Promise值
  2. 顺序保持:结果数组与输入顺序一致
  3. 短路机制:第一个rejected即终止
  4. 空数组处理:直接resolve空数组

2.2 Promise.race实现

  1. MyPromise.race = function(promises) {
  2. return new MyPromise((resolve, reject) => {
  3. if (promises.length === 0) {
  4. return; // 规范未定义空数组行为,此处保持静默
  5. }
  6. promises.forEach(promise => {
  7. MyPromise.resolve(promise).then(
  8. value => resolve(value),
  9. reason => reject(reason)
  10. );
  11. });
  12. });
  13. };

特性说明:

  1. 竞速机制:第一个完成(无论成功失败)的Promise决定结果
  2. 参数处理:同样支持非Promise值
  3. 空数组处理:规范未明确,实际实现可能挂起

三、实战应用场景

3.1 并发请求控制

  1. // 同时发起多个API请求
  2. function fetchAllData(urls) {
  3. return MyPromise.all(
  4. urls.map(url =>
  5. fetch(url).then(res => res.json())
  6. )
  7. );
  8. }
  9. // 优先获取最快响应
  10. function getFastestResponse(urls) {
  11. return MyPromise.race(
  12. urls.map(url =>
  13. fetch(url).then(res => res.json())
  14. )
  15. );
  16. }

3.2 超时控制实现

  1. function timeoutPromise(promise, ms) {
  2. return MyPromise.race([
  3. promise,
  4. new MyPromise((_, reject) =>
  5. setTimeout(() => reject(new Error('Timeout')), ms)
  6. )
  7. ]);
  8. }
  9. // 使用示例
  10. timeoutPromise(fetch('https://api.example.com'), 5000)
  11. .then(data => console.log(data))
  12. .catch(err => console.error(err.message));

四、常见问题与解决方案

4.1 内存泄漏风险

问题:未清理的回调队列可能导致内存泄漏
解决方案:

  1. // 在Promise类中添加取消机制
  2. class CancelablePromise extends MyPromise {
  3. constructor(executor) {
  4. super(executor);
  5. this.cancelHandlers = [];
  6. }
  7. cancel(reason) {
  8. this.cancelHandlers.forEach(handler => handler(reason));
  9. this.reject(new Error(`Canceled: ${reason}`));
  10. }
  11. then(onFulfilled, onRejected) {
  12. const promise2 = super.then(onFulfilled, onRejected);
  13. if (typeof onFulfilled === 'function') {
  14. this.cancelHandlers.push(() => {
  15. onFulfilled = null; // 清理引用
  16. });
  17. }
  18. return promise2;
  19. }
  20. }

4.2 错误处理最佳实践

  1. 始终在Promise链末尾添加.catch()
  2. 使用async/await时配合try-catch
  3. 区分可恢复错误和致命错误

五、性能优化建议

  1. 批量处理:对于大量Promise,考虑分批处理
  2. 并发控制:使用信号量模式限制并发数

    1. class PromisePool {
    2. constructor(maxConcurrent) {
    3. this.maxConcurrent = maxConcurrent;
    4. this.running = 0;
    5. this.queue = [];
    6. }
    7. add(promiseGenerator) {
    8. return new MyPromise((resolve, reject) => {
    9. this.queue.push({ promiseGenerator, resolve, reject });
    10. this.run();
    11. });
    12. }
    13. run() {
    14. while (this.running < this.maxConcurrent && this.queue.length) {
    15. const { promiseGenerator, resolve, reject } = this.queue.shift();
    16. this.running++;
    17. promiseGenerator()
    18. .then(resolve, reject)
    19. .finally(() => {
    20. this.running--;
    21. this.run();
    22. });
    23. }
    24. }
    25. }
  3. 缓存策略:对重复请求使用Memoization

六、总结与展望

通过手写实现Promise核心机制,我们深入理解了:

  1. 状态机的设计原理
  2. 异步调度的实现技巧
  3. 链式调用的延续性保证
  4. 错误传播的机制

未来发展方向:

  1. 支持Async/Await语法
  2. 实现Promise.try统一同步/异步错误处理
  3. 添加进度通知能力
  4. 集成取消令牌模式

完整实现代码已覆盖Promise核心功能,开发者可通过扩展上述基础实现,构建更强大的异步控制工具。建议在实际项目中先使用原生Promise,在需要特殊功能时再考虑自定义实现。

相关文章推荐

发表评论