返回

掌握Promise本质原理,携手共创全功能实现

前端

Promise,作为现代前端开发中不可或缺的异步解决方案,凭借其简洁的语法和强大的功能,受到了广泛的应用。在本文中,我们将深入浅出地剖析Promise的原理,并携手构建一个符合Promise A+规范的全功能实现。

Promise的本质与生命周期

Promise,即“承诺”,顾名思义,是一种代表异步操作最终完成或失败的容器。在JavaScript中,Promise对象具有三个状态:

  1. Pending(等待): Promise初始状态,表示异步操作尚未完成。
  2. Fulfilled(已完成): 异步操作成功完成,Promise的值已知。
  3. Rejected(已拒绝): 异步操作失败,Promise的值未知。

Promise的生命周期如下图所示:

[图片]

Promise一旦被创建,便进入Pending状态。当异步操作完成时,Promise的状态会变更为Fulfilled或Rejected,并通过resolve()或reject()方法传递相应的值。状态一旦改变,便不可逆转。

核心方法与实际应用

Promise对象提供了三个核心方法:

  1. resolve(): 将Promise的状态变更为Fulfilled,并传递一个值作为结果。
  2. reject(): 将Promise的状态变更为Rejected,并传递一个值作为错误原因。
  3. then(): 为Promise添加回调函数,当Promise状态改变时,回调函数会被自动调用。

then()方法的语法如下:

then(onFulfilled, onRejected)

其中,onFulfilled和onRejected是可选参数,分别为Promise状态变更为Fulfilled和Rejected时要执行的回调函数。

举个例子,我们有一个获取用户信息的异步函数getUser(),它会返回一个Promise对象。我们希望在用户数据获取成功时,显示用户信息,失败时,显示错误信息。我们可以使用then()方法如下实现:

getUser()
  .then(function(user) {
    // 用户数据获取成功,显示用户信息
    console.log('User:', user);
  })
  .catch(function(error) {
    // 用户数据获取失败,显示错误信息
    console.error('Error:', error);
  });

全功能实现

现在,让我们携手构建一个全功能的Promise实现。为了符合Promise A+规范,我们需要实现以下几个关键步骤:

  1. 初始化Promise对象: 构造函数接受一个执行器函数作为参数,执行器函数有两个参数,分别是resolve和reject,用于改变Promise的状态。
  2. 添加then()方法: then()方法接受两个回调函数作为参数,分别为Promise状态变更为Fulfilled和Rejected时要执行的回调函数。
  3. 处理then()方法的链式调用: Promise.prototype.then()方法可以被链式调用,即then()方法的返回值仍然是一个Promise对象。
  4. 处理异常情况: 如果resolve()或reject()方法的参数不是函数,则Promise的状态应该变更为Fulfilled或Rejected,并传递该参数作为结果。

完整的实现代码如下:

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

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

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

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

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

    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(() => {
          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) => {
        onFinally();
        return value;
      },
      (reason) => {
        onFinally();
        throw reason;
      }
    );
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    reject(new TypeError('Chaining cycle detected for promise'));
  } else if (x instanceof Promise) {
    x.then((value) => {
      resolvePromise(promise2, value, resolve, reject);
    }, reject);
  } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      const then = x.then;
      if (typeof then === 'function') {
        let called = false;
        try {
          then.call(
            x,
            (y) => {
              if (called) return;
              called = true;
              resolvePromise(promise2, y, resolve, reject);
            },
            (r) => {
              if (called) return;
              called = true;
              reject(r);
            }
          );
        } catch (error) {
          if (called) return;
          called = true;
          reject(error);
        }
      } else {
        resolve(x);
      }
    } catch (error) {
      reject(error);
    }
  } else {
    resolve(x);
  }
}

结语

至此,我们已经携手完成了Promise全功能的实现。通过这篇教程,我们不仅深入理解了Promise的原理和生命周期,还掌握了核心方法的使用和全功能实现的细节。这些知识将助你在实际开发中游刃有余地使用Promise,提升异步编程的水平。

实践是检验真理的唯一标准。不妨将本文作为起点,在实际项目中不断探索和实践,相信你会对Promise有更加深入的理解。