返回

手写PromiseA+规范及应用实例分析

前端

在繁杂的编程世界里,异步编程无疑是一股清流,它让我们得以在主线程之外执行任务,从而提高程序的执行效率。在JavaScript中,Promise便是异步编程的利器,它提供了一套规范,帮助开发者轻松处理异步操作。

邂逅PromiseA+规范,领略异步之美

PromiseA+规范是一套用于Promise实现的标准,它定义了Promise的基本行为和用法。只有遵循此规范实现的Promise才能被称为真正的Promise。

1. Promise的三种状态

每个Promise实例都有三种状态:Pending(等待)、Fulfilled(已完成)和Rejected(已拒绝)。Pending状态表示Promise还没有完成,Fulfilled状态表示Promise已成功完成,而Rejected状态表示Promise已失败。

2. Promise的链式调用

Promise支持链式调用,即在一个Promise中可以返回另一个Promise,从而形成一个Promise链。链式调用可以帮助我们更轻松地处理复杂的操作流程,提高代码的可读性和可维护性。

3. Promise.all

Promise.all方法可以同时执行多个Promise并等待所有Promise完成,然后将所有Promise的结果作为参数传递给回调函数。Promise.all非常适合处理需要同时执行多个异步操作的情况。

4. Promise.race

Promise.race方法可以同时执行多个Promise,但它只等待第一个完成的Promise,然后将该Promise的结果作为参数传递给回调函数。Promise.race非常适合处理需要竞争执行的异步操作。

5. Promise.resolve

Promise.resolve方法可以将一个值包装成一个Fulfilled状态的Promise。如果传入一个Promise实例,Promise.resolve方法将直接返回该Promise实例。

6. Promise.reject

Promise.reject方法可以将一个值包装成一个Rejected状态的Promise。如果传入一个Promise实例,Promise.reject方法将直接返回该Promise实例。

亲自操刀,手写Promise

手写Promise的过程可以帮助我们更深入地理解Promise的实现原理,同时也是对自身编程能力的挑战和提升。

1. 定义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 (error) {
      this.reject(error);
    }
  }

  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) {
    const promise2 = new Promise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else {
        this.onFulfilledCallbacks.push((value) => {
          setTimeout(() => {
            try {
              const x = onFulfilled(value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
        this.onRejectedCallbacks.push((reason) => {
          setTimeout(() => {
            try {
              const x = onRejected(reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });

    return promise2;
  }

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

  finally(onFinally) {
    const promise2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        try {
          onFinally();
          resolve(this.value);
        } catch (error) {
          reject(error);
        }
      }, 0);
    });

    return promise2;
  }

  static resolve(value) {
    return new Promise((resolve) => {
      resolve(value);
    });
  }

  static reject(reason) {
    return new Promise((_, reject) => {
      reject(reason);
    });
  }

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

      promises.forEach((promise, index) => {
        promise.then(
          (value) => {
            results[index] = value;
            count++;

            if (count === promises.length) {
              resolve(results);
            }
          },
          (reason) => {
            reject(reason);
          }
        );
      });
    });
  }

  static race(promises) {
    return new Promise((resolve, reject) => {
      promises.forEach((promise) => {
        promise.then(
          (value) => {
            resolve(value);
          },
          (reason) => {
            reject(reason);
          }
        );
      });
    });
  }
}

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

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

      if (typeof then === 'function') {
        then.call(
          x,
          (y) => {
            resolvePromise(promise2, y, resolve, reject);
          },
          (reason) => {
            reject(reason);
          }
        );
      } else {
        resolve(x);
      }
    } catch (error) {
      reject(error);
    }
  } else {
    resolve(x);
  }
}

2. Promise的使用示例

// 创建一个Promise实例
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('Hello, Promise!');
  }, 1000);
});

// 使用then方法处理Promise的结果
promise.then((result) => {
  console.log(result); // 输出: Hello, Promise!
});

// 使用catch方法处理Promise的失败
promise.catch((error) => {
  console.log(error); // 输出: Error: Something went wrong!
});

// 使用finally方法无论Promise成功还是失败都会执行
promise.finally(() => {
  console.log('Finally!'); // 输出: Finally!
});

// 使用Promise.all方法同时执行多个Promise
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);

Promise.all([promise1, promise2, promise3]).then((results) => {
  console.log(results); // 输出: [1, 2, 3]
});

// 使用Promise.