返回

迈向更好实践——剖析基于Promise/A+规范的Promises实现

前端

在软件开发的世界里,我们常常需要处理异步任务,也就是那些需要等待一段时间才能完成的任务。传统上,我们使用回调函数来处理这些任务,但这种方式很容易导致代码混乱和难以维护。Promise是一种更好的方式来处理异步任务,它可以使代码更易读、更易维护。

Promise是一个JavaScript对象,它代表一个即将完成或已经完成的异步操作。它有三个状态:

  • Pending: Promise处于初始状态,尚未完成。
  • Fulfilled: Promise已成功完成,并带有结果值。
  • Rejected: Promise已失败,并带有错误信息。

Promise可以通过then方法来注册回调函数。当Promise的状态发生改变时,相应的回调函数就会被调用。

const promise = new Promise((resolve, reject) => {
  // 异步操作
});

promise.then((result) => {
  // Promise成功完成时的回调函数
}, (error) => {
  // Promise失败时的回调函数
});

以上是一个Promise的简单示例。Promise的构造函数接受两个参数,resolve和reject。resolve函数用于在Promise成功完成时调用,reject函数用于在Promise失败时调用。then方法接受两个参数,分别是成功回调函数和失败回调函数。当Promise的状态发生改变时,相应的回调函数就会被调用。

Promise/A+规范定义了Promise的标准行为。这个规范确保了所有实现Promise的JavaScript库都具有相同的基本行为。这使得开发人员可以在不同的库之间轻松切换,而不用担心兼容性问题。

要实现Promise/A+规范,我们需要实现以下方法:

  • 构造函数: 初始化Promise并接受两个参数,resolve和reject。
  • then方法: 注册回调函数。
  • resolvePromise方法: 将Promise的状态设置为Fulfilled,并带有结果值。
  • finally方法: 无论Promise的状态如何,都会执行的回调函数。
  • catch方法: 注册失败回调函数。

以下是一个基于Promise/A+规范的Promises实现:

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

    const resolve = (result) => {
      if (this.state !== 'pending') {
        return;
      }

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

      this.onFulfilledCallbacks.forEach((callback) => {
        callback(result);
      });
    };

    const reject = (error) => {
      if (this.state !== 'pending') {
        return;
      }

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

      this.onRejectedCallbacks.forEach((callback) => {
        callback(error);
      });
    };

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

  then(onFulfilled, onRejected) {
    return new Promise((resolve, reject) => {
      const handleFulfilled = (result) => {
        try {
          const result2 = onFulfilled(result);
          resolve(result2);
        } catch (error) {
          reject(error);
        }
      };

      const handleRejected = (error) => {
        try {
          const result2 = onRejected(error);
          resolve(result2);
        } catch (error) {
          reject(error);
        }
      };

      if (this.state === 'pending') {
        this.onFulfilledCallbacks.push(handleFulfilled);
        this.onRejectedCallbacks.push(handleRejected);
      } else if (this.state === 'fulfilled') {
        setTimeout(() => {
          handleFulfilled(this.result);
        }, 0);
      } else if (this.state === 'rejected') {
        setTimeout(() => {
          handleRejected(this.result);
        }, 0);
      }
    });
  }

  resolvePromise(promise2, x) {
    if (promise2 === x) {
      throw new TypeError('Chaining cycle detected for promise!');
    }

    if (x instanceof Promise) {
      x.then((result) => {
        this.resolvePromise(promise2, result);
      }, (error) => {
        reject(error);
      });
    } else if (x && (typeof x === 'object' || typeof x === 'function')) {
      let then;
      try {
        then = x.then;
      } catch (error) {
        reject(error);
      }

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

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

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

这是一个简单的基于Promise/A+规范的Promises实现。它实现了构造函数、then方法、resolvePromise方法、finally方法和catch方法。

Promise可以用于处理各种各样的异步任务,如网络请求、文件读取、定时器等。它可以使代码更易读、更易维护,并提高开发效率。