JavaScript Promise 深入解析与实现:从基础到高级应用

256 阅读7分钟

引言

在JavaScript中,异步编程是一个常见的需求。传统的回调函数方式容易导致“回调地狱”,使代码难以维护。为了解决这个问题,ES6引入了Promise对象,用于更优雅地处理异步操作。本文将介绍Promise的状态、方法,并展示如何在JavaScript中封装Promise,实现其核心方法,并在Function原型链中实现这些方法。

Snipaste_2025-02-20_16-57-20.png

Promise状态介绍

Promise对象有三种状态:

  1. Pending(待定):初始状态,既不是成功也不是失败。
  2. Fulfilled(已兑现):操作成功完成。
  3. Rejected(已拒绝):操作失败。

状态一旦改变,就不能再变。Promise对象从Pending状态变为Fulfilled或Rejected状态后,会调用相应的处理函数。

Promise方法介绍

Promise对象有以下几种方法:

  1. then(onFulfilled, onRejected):添加成功和失败的回调函数。
  2. catch(onRejected):添加失败的回调函数。
  3. resolve(value):返回一个状态为Fulfilled的Promise对象。
  4. reject(reason):返回一个状态为Rejected的Promise对象。
  5. all(promises):接收一个Promise数组,返回一个新的Promise,只有当所有Promise都成功时才成功。
  6. race(promises):接收一个Promise数组,返回一个新的Promise,哪个Promise先完成就返回哪个Promise的结果。

封装Promise

下面是一个在JavaScript中封装Promise的实现,并在Function原型链中实现其核心方法。

class MyPromise {
  constructor(executor) {
    // 初始状态为 pending
    this.state = 'pending';
    // 成功的值
    this.value = undefined;
    // 失败的原因
    this.reason = undefined;
    // 成功回调函数队列
    this.onFulfilledCallbacks = [];
    // 失败回调函数队列
    this.onRejectedCallbacks = [];

    // resolve 函数
    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        // 执行所有成功回调
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };

    // reject 函数
    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        // 执行所有失败回调
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };

    // 执行 executor 函数,并传入 resolve 和 reject
    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }

  // then 方法
  then(onFulfilled, onRejected) {
    // 如果 onFulfilled 不是函数,给一个默认函数,返回 value
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    // 如果 onRejected 不是函数,给一个默认函数,抛出 reason
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    // 返回一个新的 Promise
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        // 异步执行 onFulfilled
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);
            // 解析 x
            resolvePromise(promise2, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        });
      }

      if (this.state === 'rejected') {
        // 异步执行 onRejected
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            // 解析 x
            resolvePromise(promise2, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        });
      }

      if (this.state === 'pending') {
        // 如果状态是 pending,将 onFulfilled 和 onRejected 存入队列
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value);
              // 解析 x
              resolvePromise(promise2, x, resolve, reject);
            } catch (err) {
              reject(err);
            }
          });
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);
              // 解析 x
              resolvePromise(promise2, x, resolve, reject);
            } catch (err) {
              reject(err);
            }
          });
        });
      }
    });

    return promise2;
  }

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

  // 静态 resolve 方法
  static resolve(value) {
    return new MyPromise((resolve, reject) => {
      resolve(value);
    });
  }

  // 静态 reject 方法
  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason);
    });
  }

  // 静态 all 方法
  static all(promises) {
    return new MyPromise((resolve, reject) => {
      let result = [];
      let count = 0;

      function processData(index, data) {
        result[index] = data;
        if (++count === promises.length) {
          resolve(result);
        }
      }

      for (let i = 0; i < promises.length; i++) {
        promises[i].then(data => {
          processData(i, data);
        }, reject);
      }
    });
  }

  // 静态 race 方法
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(resolve, reject);
      }
    });
  }
}

// 解析 Promise 的结果
function resolvePromise(promise2, x, resolve, reject) {
  // 如果 promise2 和 x 指向同一个对象,抛出类型错误,防止循环引用
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise'));
  }

  // 用于标记是否已经调用过 resolve 或 reject,防止多次调用
  let called;
  
  // 如果 x 不为 null 且 x 是对象或函数
  if (x != null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      // 尝试取 x.then,可能会抛出错误
      let then = x.then;

      // 如果 then 是函数,认为 x 是一个 promise
      if (typeof then === 'function') {
        // 调用 then,并将 this 指向 x
        then.call(x, y => {
          // 如果已经调用过 resolve 或 reject,直接返回
          if (called) return;
          called = true;
          // 递归解析 y,防止 y 也是一个 promise
          resolvePromise(promise2, y, resolve, reject);
        }, err => {
          // 如果已经调用过 resolve 或 reject,直接返回
          if (called) return;
          called = true;
          // 如果出错,直接 reject
          reject(err);
        });
      } else {
        // 如果 then 不是函数,说明 x 不是一个 promise,直接 resolve
        resolve(x);
      }
    } catch (err) {
      // 如果取 then 时抛出错误,且没有调用过 resolve 或 reject,直接 reject
      if (called) return;
      called = true;
      reject(err);
    }
  } else {
    // 如果 x 不是对象或函数,直接 resolve
    resolve(x);
  }
}

// 在Function原型链中实现
Function.prototype.resolve = MyPromise.resolve;
Function.prototype.reject = MyPromise.reject;
Function.prototype.all = MyPromise.all;
Function.prototype.race = MyPromise.race;

// 使用方法
const promise1 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('Promise 1 resolved');
  }, 1000);
});

const promise2 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('Promise 2 resolved');
  }, 2000);
});

promise1.then(value => {
  console.log(value);
  return promise2;
}).then(value => {
  console.log(value);
}).catch(err => {
  console.error(err);
});

MyPromise.all([promise1, promise2]).then(values => {
  console.log('All promises resolved:', values);
}).catch(err => {
  console.error(err);
});

MyPromise.race([promise1, promise2]).then(value => {
  console.log('Race winner:', value);
}).catch(err => {
  console.error(err);
});

详细描述

  1. 构造函数

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

    初始化Promise的状态为pending,并定义成功值、失败原因和回调函数队列。

  2. resolve函数

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

    将Promise的状态从pending变为fulfilled,并执行所有成功回调。

  3. reject函数

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

    将Promise的状态从pending变为rejected,并执行所有失败回调。

  4. then方法

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

    then方法接收两个回调函数,并返回一个新的Promise。

  5. catch方法

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

    catch方法是then方法的语法糖,只接收失败回调。

  6. 静态resolve方法

    static resolve(value) {
      return new MyPromise((resolve, reject) => {
        resolve(value);
      });
    }
    

    返回一个状态为fulfilled的Promise。

  7. 静态reject方法

    static reject(reason) {
      return new MyPromise((resolve, reject) => {
        reject(reason);
      });
    }
    

    返回一个状态为rejected的Promise。

  8. 静态all方法

    static all(promises) {
      return new MyPromise((resolve, reject) => {
        let result = [];
        let count = 0;
    
        function processData(index, data) {
          result[index] = data;
          if (++count === promises.length) {
            resolve(result);
          }
        }
    
        for (let i = 0; i < promises.length; i++) {
          promises[i].then(data => {
            processData(i, data);
          }, reject);
        }
      });
    }
    

    接收一个Promise数组,只有当所有Promise都成功时才成功。

  9. 静态race方法

    static race(promises) {
      return new MyPromise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
          promises[i].then(resolve, reject);
        }
      });
    }
    

    接收一个Promise数组,哪个Promise先完成就返回哪个Promise的结果。

  10. resolvePromise函数

    function resolvePromise(promise2, x, resolve, reject) {
      // 如果 promise2 和 x 指向同一个对象,抛出类型错误,防止循环引用
      if (promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise'));
      }
    
      // 用于标记是否已经调用过 resolve 或 reject,防止多次调用
      let called;
      
      // 如果 x 不为 null 且 x 是对象或函数
      if (x != null && (typeof x === 'object' || typeof x === 'function')) {
        try {
          // 尝试取 x.then,可能会抛出错误
          let then = x.then;
    
          // 如果 then 是函数,认为 x 是一个 promise
          if (typeof then === 'function') {
            // 调用 then,并将 this 指向 x
            then.call(x, y => {
              // 如果已经调用过 resolve 或 reject,直接返回
              if (called) return;
              called = true;
              // 递归解析 y,防止 y 也是一个 promise
              resolvePromise(promise2, y, resolve, reject);
            }, err => {
              // 如果已经调用过 resolve 或 reject,直接返回
              if (called) return;
              called = true;
              // 如果出错,直接 reject
              reject(err);
            });
          } else {
            // 如果 then 不是函数,说明 x 不是一个 promise,直接 resolve
            resolve(x);
          }
        } catch (err) {
          // 如果取 then 时抛出错误,且没有调用过 resolve 或 reject,直接 reject
          if (called) return;
          called = true;
          reject(err);
        }
      } else {
        // 如果 x 不是对象或函数,直接 resolve
        resolve(x);
      }
    }
    

    这个函数用于解析Promise的结果,处理Promise链中的值,防止循环引用,并确保Promise的状态只改变一次。

使用场景和返回结果

  1. then方法

    • 使用场景:处理Promise成功或失败的结果。
    • 返回结果:返回一个新的Promise,可以链式调用。
    promise1.then(value => {
      console.log(value); // Promise 1 resolved
      return promise2;
    }).then(value => {
      console.log(value); // Promise 2 resolved
    }).catch(err => {
      console.error(err);
    });
    
  2. catch方法

    • 使用场景:处理Promise失败的结果。
    • 返回结果:返回一个新的Promise,可以链式调用。
    promise1.catch(err => {
      console.error(err);
    });
    
  3. 静态resolve方法

    • 使用场景:创建一个状态为fulfilled的Promise。
    • 返回结果:返回一个状态为fulfilled的Promise。
    MyPromise.resolve('Success').then(value => {
      console.log(value); // Success
    });
    
  4. 静态reject方法

    • 使用场景:创建一个状态为rejected的Promise。
    • 返回结果:返回一个状态为rejected的Promise。
    MyPromise.reject('Error').catch(reason => {
      console.error(reason); // Error
    });
    
  5. 静态all方法

    • 使用场景:等待所有Promise都成功。
    • 返回结果:返回一个新的Promise,只有当所有Promise都成功时才成功。
    MyPromise.all([promise1, promise2]).then(values => {
      console.log('All promises resolved:', values);
      // All promises resolved: ['Promise 1 resolved', 'Promise 2 resolved']
    }).catch(err => {
      console.error(err);
    });
    
  6. 静态race方法

    • 使用场景:等待第一个完成的Promise。
    • 返回结果:返回一个新的Promise,哪个Promise先完成就返回哪个Promise的结果。
    MyPromise.race([promise1, promise2]).then(value => {
      console.log('Race winner:', value); // Race winner: Promise 1 resolved
    }).catch(err => {
      console.error(err);
    });
    

通过详细的注释和解释,希望你能更好地理解MyPromise类及其resolvePromise函数的实现原理,以及每个方法的使用场景和返回结果。

找到具有 1 个许可证类型的类似代码