Skip to content
Go back

Promise的实现原理详解

Published:  at  04:12 PM

文章目录

一、基础概念理解

1.0 Promise的简化代码逻辑

// 以es5为例
function MyPromise(exec){
  this.state = 'pending'; // 初始状态
  this.data = undefined; // 存储结果 / 错误原因
  this.onFulfilledCallbacks = []; // 成功回调队列
  this.onRejectedCallbacks = []; // 失败回调队列
  function resolve(value){
    // 1. vlaue是Promise类型,需判断状态,重新包裹成Promise
    // 2. vlaue非Promise类型,说明是同步代码,直接改变当前Promise状态,设置Promise的成功结果,执行成功回调队列
    // ...
  }
  function reject(reason){
    // 1. 直接修改Promise状态,设置Promise的失败原因,执行失败回调队列
    // ...
  }
  try {
    exec(resolve, reject);
  } catch (error) {
    reject(error)
  }
}

const resolvePromise = (promise2, x, resolve, reject) => {
  // 判断链式是否无限循环
  if (promise2 === x)  return reject(new TypeError('Chaining cycle detected for promise!'))

  // ...

  // 循环递归直至promise为非pending态
  let then = x.then;
  if (typeof then === 'function') {
    then.call(
      x,
      y => resolvePromise(promise2, y, resolve, reject),
      r => reject(r)
    );
  } else {
    resolve(x);
  }
}

MyPromise.prototype.then = function (onResolved, onRejected) {
    var self = this;
    var promise2;

    onResolved = typeof onResolved === 'function' ? onResolved : function (value) { return value };
    onRejected = typeof onRejected === 'function' ? onRejected : function (reason) { throw reason };

    if (self.status === 'resolved') {
      // 1. 当前Promise已完成,可直接调用户的resolve方法,返回值可能有
      //    - 普通值:直接resolve
      //    - Promise对象:等待其状态变化
      // 2. then返回值均为Promise,需对用户resolve方法的返回值,再做Promise包裹
      // 3. resolvePromise处理各种返回值类型,直至所有异步态结束
    }

    if (self.status === 'rejected') {
      // 1. 同resolve相关逻辑,区别在于,调用户的reject方法获取当前Promise的值
    }

    if (self.status === 'pending') {
      // 1. 当前Promise未完成,不能立即调用户的resolve或者reject方法
      // 2. 使用成功回调队列和失败回调队列,先存储调用对应方法的回调
    }
}

1.1 Promise的状态机

Promise是一种异步编程解决方案,它有三种状态:

状态转换规则:

1.2 状态转换规则

Promise的状态一旦改变就不能再修改。这种不可变性是Promise设计的核心原则之一。

1.3 then方法的链式调用原理

then方法返回的是一个新的Promise实例,而不是原来的Promise实例。这使得链式调用成为可能:

promise
  .then(result => {
    // 处理结果
    return processResult(result);
  })
  .then(processedResult => {
    // 继续处理
    return finalResult(processedResult);
  })
  .catch(error => {
    // 捕获错误
  });

1.4 微任务队列机制

Promise的回调是通过微任务队列执行的,这保证了异步操作的顺序性。微任务会在当前宏任务执行结束后立即执行。

二、核心数据结构设计

2.1 Promise构造函数

class MyPromise {
  constructor(executor) {
    this.state = 'pending'; // 初始状态
    this.value = undefined; // 存储结果
    this.reason = undefined; // 存储错误原因
    this.onFulfilledCallbacks = []; // 成功回调队列
    this.onRejectedCallbacks = []; // 失败回调队列

    // 执行器函数
    try {
      executor(this.resolve, this.reject);
    } catch (error) {
      this.reject(error);
    }
  }
}

2.2 状态管理

状态管理需要确保状态只能改变一次:

resolve = (value) => {
  if (this.state === 'pending') {
    this.state = 'fulfilled';
    this.value = value;
    // 执行所有成功回调
    this.onFulfilledCallbacks.forEach(callback => callback(value));
  }
}

reject = (reason) => {
  if (this.state === 'pending') {
    this.state = 'rejected';
    this.reason = reason;
    // 执行所有失败回调
    this.onRejectedCallbacks.forEach(callback => callback(reason));
  }
}

2.3 回调队列

回调队列用于存储then方法注册的回调函数,直到Promise状态改变时再执行。

2.4 值传递机制

值传递需要处理thenable对象和Promise的穿透特性:

// 处理thenable对象
const resolvePromise = (promise2, x, resolve, reject) => {
  // 以防这种情况
  // const p = Promise.resolve().then(()=>p)
  // then方法返回的Promise 和 ()=>p 返回的Promise是同一个
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected'));
  }

  if ((x !== null && typeof x === 'object') || typeof x === 'function') {
    try {
      let then = x.then;
      if (typeof then === 'function') {
        then.call(
          x,
          y => resolvePromise(promise2, y, resolve, reject),
          r => reject(r)
        );
      } else {
        resolve(x);
      }
    } catch (error) {
      reject(error);
    }
  } else {
    resolve(x);
  }
}

三、关键方法实现

3.1 then方法

then(onFulfilled, onRejected) {
  // 确保onFulfilled和onRejected是函数
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
  onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

  // 创建新的Promise
  const promise2 = new MyPromise((resolve, reject) => {
    if (this.state === 'fulfilled') {
      setTimeout(() => {
        try {
          const x = onFulfilled(this.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (error) {
          reject(error);
        }
      }, 0);
    }

    if (this.state === 'rejected') {
      setTimeout(() => {
        try {
          const x = onRejected(this.reason);
          resolvePromise(promise2, x, resolve, reject);
        } catch (error) {
          reject(error);
        }
      }, 0);
    }

    if (this.state === 'pending') {
      this.onFulfilledCallbacks.push(() => {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      });

      this.onRejectedCallbacks.push(() => {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      });
    }
  });

  return promise2;
}

3.2 resolve/reject函数

resolve和reject函数需要处理以下情况:

  1. 传入Promise对象时,需要等待其状态改变
  2. 传入thenable对象时,需要调用其then方法
  3. 传入普通值时,直接改变状态

3.3 链式调用处理

链式调用的核心是每个then方法都返回一个新的Promise,并且需要处理返回值的穿透特性。

3.4 错误处理机制

错误处理需要考虑:

  1. 执行器函数中的同步错误
  2. then方法中回调函数的执行错误
  3. 链式调用中的错误传递

四、完整代码实现

// 基础Promise类
class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.onFulfilledCallbacks.forEach(callback => callback());
      }
    }

    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(callback => callback());
      }
    }

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    const promise2 = new MyPromise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      if (this.state === 'pending') {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });

    return promise2;
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }

  finally(onFinally) {
    return this.then(
      value => MyPromise.resolve(onFinally()).then(() => value),
      reason => MyPromise.resolve(onFinally()).then(() => { throw reason })
    );
  }
}

const resolvePromise = (promise2, x, resolve, reject) => {
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected'));
  }

  if ((x !== null && typeof x === 'object') || typeof x === 'function') {
    try {
      let then = x.then;
      // 判断是否thenable
      if (typeof then === 'function') {
        then.call(
          x,
          y => resolvePromise(promise2, y, resolve, reject),
          r => reject(r)
        );
      } else {
        resolve(x);
      }
    } catch (error) {
      reject(error);
    }
  } else {
    resolve(x);
  }
}

// 静态方法
MyPromise.resolve = (value) => {
  if (value instanceof MyPromise) return value;
  return new MyPromise(resolve => resolve(value));
}

MyPromise.reject = (reason) => {
  return new MyPromise((resolve, reject) => reject(reason));
}

MyPromise.all = (promises) => {
  return new MyPromise((resolve, reject) => {
    const results = [];
    let completedCount = 0;

    promises.forEach((promise, index) => {
      MyPromise.resolve(promise).then(
        value => {
          results[index] = value;
          completedCount++;
          if (completedCount === promises.length) {
            resolve(results);
          }
        },
        reason => reject(reason)
      );
    });
  });
}

MyPromise.race = (promises) => {
  return new MyPromise((resolve, reject) => {
    promises.forEach(promise => {
      MyPromise.resolve(promise).then(resolve, reject);
    });
  });
}

// 测试代码
const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功');
  }, 1000);
});

promise
  .then(result => {
    console.log('Result:', result);
    return '处理后的数据';
  })
  .then(processedResult => {
    console.log('Processed:', processedResult);
    throw new Error('测试错误');
  })
  .catch(error => {
    console.error('Error:', error.message);
  });

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

// Promise.race测试
MyPromise.race([
  new MyPromise(resolve => setTimeout(() => resolve('第一个完成'), 500)),
  new MyPromise(resolve => setTimeout(() => resolve('第二个完成'), 1000))
]).then(result => console.log('Race result:', result));

总结

Promise的实现原理涉及状态管理、回调队列、微任务机制等多个核心概念。通过理解这些原理,我们可以更好地使用Promise进行异步编程,并且在需要时实现自定义的Promise类。

完整的Promise实现需要考虑很多边界情况和规范细节,上述代码是一个简化的版本,实际的Promise/A+规范要复杂得多。建议在学习过程中结合规范文档和测试用例进行深入理解。



Previous Post
React + Svg 实现环形图组件
Next Post
Tailwindcss之用法