返回

手把手教你用Promises/A+规范自己动手实现一个Promise

前端

在上一篇文章《JavaScript Promise基础》中,我们介绍了Promise的基本使用。如果你对Promise的用法还不熟悉,强烈建议先阅读那篇文章,然后再阅读本文。在本文中,我们将根据 Promises/A+ 规范,自己动手实现一个Promise,以便更深入地理解Promise的原理和用法。

Promises/A+规范是什么?

Promises/A+规范是由若干浏览器厂商和JavaScript专家共同制定的,它定义了Promise对象的行为和用法,确保不同浏览器和JavaScript引擎实现的Promise对象具有相同的功能和用法。这使得我们可以放心地在任何浏览器和JavaScript引擎中使用Promise,而无需担心兼容性问题。

如何实现一个Promise?

实现一个Promise对象需要遵循Promises/A+规范的要求,主要步骤如下:

  1. 创建一个Promise对象,并传入一个执行器函数作为参数。
  2. 在执行器函数中,通过resolve()方法或reject()方法来改变Promise对象的状态。
  3. 当Promise对象的状态发生改变时,触发对应的回调函数。

下面是一个简单的Promise实现示例:

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

    try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (err) {
      this.reject(err);
    }
  }

  resolve(value) {
    if (this.state !== 'pending') {
      return;
    }

    this.state = 'fulfilled';
    this.value = value;
    this.onFulfilledCallbacks.forEach(callback => callback(value));
  }

  reject(reason) {
    if (this.state !== 'pending') {
      return;
    }

    this.state = 'rejected';
    this.reason = reason;
    this.onRejectedCallbacks.forEach(callback => callback(reason));
  }

  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = value => value;
    }

    if (typeof onRejected !== 'function') {
      onRejected = reason => { throw reason; };
    }

    const promise2 = new Promise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        }, 0);
      } else if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        }, 0);
      } else {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (err) {
              reject(err);
            }
          }, 0);
        });

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

    return promise2;
  }

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

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

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

  if (x instanceof Promise) {
    x.then(value => resolvePromise(promise2, value, resolve, reject), reason => reject(reason));
  } else if (x && (typeof x === 'object' || typeof x === 'function')) {
    let then;
    try {
      then = x.then;
    } catch (err) {
      reject(err);
      return;
    }

    if (typeof then === 'function') {
      let called = false;
      try {
        then.call(
          x,
          value => {
            if (called) return;
            called = true;
            resolvePromise(promise2, value, resolve, reject);
          },
          reason => {
            if (called) return;
            called = true;
            reject(reason);
          }
        );
      } catch (err) {
        if (called) return;
        reject(err);
      }
    } else {
      resolve(x);
    }
  } else {
    resolve(x);
  }
}

这个简单的Promise实现虽然功能上与原生Promise对象基本相同,但还不够完善。例如,它没有处理Promise对象的状态改变时的微任务队列,也没有考虑Promise对象的链式调用等。如果需要实现一个更完整的Promise对象,需要对这个示例代码进行更多的完善。

总结

本文介绍了如何根据Promises/A+规范自己动手实现一个Promise对象,帮助读者深入理解Promise的原理和用法。在实际开发中,我们可以使用原生Promise对象,也可以使用第三方库实现的Promise对象。但无论如何,理解Promise的原理对于我们正确使用Promise对象非常重要。