返回

重塑可靠承诺:深入探索Promise实现的艺术

前端

拥抱异步编程新范式:深入浅出解剖Promise

缘起:告别回调地狱

在异步编程的领域,回调函数曾独领风骚。然而,随着异步操作的日益繁复,回调地狱的幽灵也随之而来。嵌套的回调函数层层叠加,代码结构变得难以维护和理解。为了解决这一痛点,Promise应运而生。

Promise的本质:占位符与优雅处理

Promise,意为“承诺”,本质上是一种表示异步操作最终完成或失败的占位符。它提供了一种更优雅的方式来处理异步操作的结果,避免回调地狱的困扰。Promise具有三个状态:等待、已完成和已拒绝。

构建自己的Promise:理解其运作原理

为了更深入理解Promise的运作机制,不妨亲手构建一个基于A+规范的Promise实现。A+规范定义了Promise的标准行为,确保不同实现之间的一致性。代码如下:

// Promise 实现
class Promise {
  constructor(executor) {
    this.state = 'pending';
    this.result = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    // 立即执行executor,传入resolve和reject函数
    try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }

  resolve(result) {
    // 确保resolve和reject只能调用一次
    if (this.state !== 'pending') {
      return;
    }

    this.state = 'fulfilled';
    this.result = result;

    // 依次调用所有已注册的onFulfilled回调函数
    this.onFulfilledCallbacks.forEach(callback => callback(result));
  }

  reject(error) {
    // 确保resolve和reject只能调用一次
    if (this.state !== 'pending') {
      return;
    }

    this.state = 'rejected';
    this.result = error;

    // 依次调用所有已注册的onRejected回调函数
    this.onRejectedCallbacks.forEach(callback => callback(error));
  }

  then(onFulfilled, onRejected) {
    // 允许then方法可以不传参数
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error; };

    // 返回一个新的Promise
    return new Promise((resolve, reject) => {
      // 根据当前Promise的状态,立即调用相应的回调函数
      if (this.state === 'fulfilled') {
        setTimeout(() => {
          try {
            const result = onFulfilled(this.result);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            const error = onRejected(this.result);
            resolve(error);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else {
        // 如果当前Promise仍处于等待状态,将回调函数加入相应的队列
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const result = onFulfilled(this.result);
              resolve(result);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

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

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

  finally(onFinally) {
    return this.then(
      result => {
        onFinally();
        return result;
      },
      error => {
        onFinally();
        throw error;
      }
    );
  }
}

ES6-Promise:标准化实现

ES6-Promise作为Promise的标准实现,在浏览器和Node.js中都得到了广泛支持。它的实现更为精巧,提供了更丰富的功能。代码如下:

// ES6-Promise 实现
class Promise {
  constructor(executor) {
    this._state = 'pending';
    this._result = undefined;
    this._onFulfilledCallbacks = [];
    this._onRejectedCallbacks = [];

    // 立即执行executor,传入resolve和reject函数
    try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }

  resolve(result) {
    // 确保resolve和reject只能调用一次
    if (this._state !== 'pending') {
      return;
    }

    this._state = 'fulfilled';
    this._result = result;

    // 依次调用所有已注册的onFulfilled回调函数
    this._onFulfilledCallbacks.forEach(callback => callback(result));
  }

  reject(error) {
    // 确保resolve和reject只能调用一次
    if (this._state !== 'pending') {
      return;
    }

    this._state = 'rejected';
    this._result = error;

    // 依次调用所有已注册的onRejected回调函数
    this._onRejectedCallbacks.forEach(callback => callback(error));
  }

  then(onFulfilled, onRejected) {
    // 允许then方法可以不传参数
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error; };

    // 返回一个新的Promise
    return new Promise((resolve, reject) => {
      // 根据当前Promise的状态,立即调用相应的回调函数
      if (this._state === 'fulfilled') {
        setTimeout(() => {
          try {
            const result = onFulfilled(this._result);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this._state === 'rejected') {
        setTimeout(() => {
          try {
            const error = onRejected(this._result);
            resolve(error);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else {
        // 如果当前Promise仍处于等待状态,将回调函数加入相应的队列
        this._onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const result = onFulfilled(this._result);
              resolve(result);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

        this._onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const error = onRejected(this._result);
              resolve(error);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });
  }

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

  finally(onFinally) {
    return this.then(
      result => {
        onFinally();
        return result;
      },
      error => {
        onFinally();
        throw error;
      }
    );
  }

  // ES6-Promise新增的静态方法
  static resolve(value) {
    return new Promise((resolve, reject) => {
      resolve(value);
    });
  }

  static reject(error) {
    return new Promise((resolve, reject) => {
      reject(error);
    });
  }

  static all(promises) {
    return new Promise((resolve, reject) => {
      const results = [];
      let pendingCount = promises.length;

      promises.forEach((promise, index) => {
        promise
          .then(result => {
            results[index] = result;
            pendingCount--;
            if (pendingCount === 0) {
              resolve(results);
            }
          })
          .catch(error => {
            reject(error);
          });
      });
    });
  }
}

常见问题解答

1. Promise与回调函数有什么区别?

Promise提供了一种更优雅的方式来处理异步操作的结果,避免回调地狱的困扰。Promise允许使用链式调用,使代码结构更加清晰易读