Skip to content

Promise实现

Promise是JavaScript中处理异步操作的重要概念,它提供了一种优雅的方式来处理异步代码,避免了回调地狱。本文件将详细介绍Promise的实现原理和代码实现。

核心概念

什么是Promise?

Promise是一个对象,它代表了一个异步操作的最终完成(或失败)及其结果值。Promise有三种状态:

  • pending:初始状态,既不是成功,也不是失败状态
  • fulfilled:操作成功完成
  • rejected:操作失败

Promise的特点

  1. 状态一旦改变,就不会再变:Promise的状态只能从pending变为fulfilled,或者从pending变为rejected,一旦状态改变,就不会再变
  2. 链式调用:Promise支持链式调用,通过then方法可以处理异步操作的结果
  3. 错误捕获:Promise支持通过catch方法捕获错误
  4. Promise.all:可以并行处理多个Promise
  5. Promise.race:可以处理多个Promise,返回第一个完成的Promise

实现原理

Promise的实现原理基于以下几个核心概念:

  1. 状态管理:管理Promise的三种状态(pending、fulfilled、rejected)
  2. 回调队列:存储then和catch方法注册的回调函数
  3. 异步处理:使用setTimeout等异步方法确保回调函数在Promise状态改变后执行
  4. 链式调用:then方法返回一个新的Promise,支持链式调用

实现代码

基础版本

javascript
class MyPromise {
  constructor(executor) {
    // 初始化状态
    this.state = 'pending';
    // 存储结果
    this.value = undefined;
    // 存储错误
    this.reason = undefined;
    // 存储成功回调
    this.onFulfilledCallbacks = [];
    // 存储失败回调
    this.onRejectedCallbacks = [];

    // 成功回调
    const resolve = (value) => {
      // 只有状态为pending时才可以改变状态
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        // 执行所有成功回调
        this.onFulfilledCallbacks.forEach(callback => callback(value));
      }
    };

    // 失败回调
    const reject = (reason) => {
      // 只有状态为pending时才可以改变状态
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        // 执行所有失败回调
        this.onRejectedCallbacks.forEach(callback => callback(reason));
      }
    };

    // 执行executor函数
    try {
      executor(resolve, reject);
    } catch (error) {
      // 如果executor执行出错,直接reject
      reject(error);
    }
  }

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

    // 返回一个新的Promise
    const promise2 = new MyPromise((resolve, reject) => {
      // 处理fulfilled状态
      if (this.state === 'fulfilled') {
        // 使用setTimeout确保回调函数异步执行
        setTimeout(() => {
          try {
            // 执行onFulfilled回调
            const x = onFulfilled(this.value);
            // 处理回调返回值
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            // 如果回调执行出错,reject
            reject(error);
          }
        }, 0);
      }

      // 处理rejected状态
      if (this.state === 'rejected') {
        // 使用setTimeout确保回调函数异步执行
        setTimeout(() => {
          try {
            // 执行onRejected回调
            const x = onRejected(this.reason);
            // 处理回调返回值
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            // 如果回调执行出错,reject
            reject(error);
          }
        }, 0);
      }

      // 处理pending状态
      if (this.state === 'pending') {
        // 将回调函数存储到队列中
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

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

    return promise2;
  }

  // 处理回调返回值
  resolvePromise(promise2, x, resolve, reject) {
    // 如果promise2和x是同一个对象,抛出错误
    if (promise2 === x) {
      return reject(new TypeError('Chaining cycle detected for promise'));
    }

    // 如果x是Promise对象
    if (x instanceof MyPromise) {
      x.then(
        value => this.resolvePromise(promise2, value, resolve, reject),
        reason => reject(reason)
      );
    } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
      // 如果x是对象或函数
      let called = false;
      try {
        const then = x.then;
        if (typeof then === 'function') {
          // 如果x有then方法,将其视为Promise
          then.call(
            x,
            value => {
              if (called) return;
              called = true;
              this.resolvePromise(promise2, value, resolve, reject);
            },
            reason => {
              if (called) return;
              called = true;
              reject(reason);
            }
          );
        } else {
          // 如果x没有then方法,直接resolve
          resolve(x);
        }
      } catch (error) {
        if (called) return;
        called = true;
        reject(error);
      }
    } else {
      // 如果x是基本类型,直接resolve
      resolve(x);
    }
  }

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

  // finally方法
  finally(callback) {
    return this.then(
      value => MyPromise.resolve(callback()).then(() => value),
      reason => MyPromise.resolve(callback()).then(() => { throw reason })
    );
  }

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

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

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

      for (let i = 0; i < promises.length; i++) {
        MyPromise.resolve(promises[i]).then(
          value => {
            results[i] = value;
            count++;
            if (count === promises.length) {
              resolve(results);
            }
          },
          reason => {
            reject(reason);
          }
        );
      }
    });
  }

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

  // 静态方法allSettled
  static allSettled(promises) {
    return new MyPromise((resolve) => {
      const results = [];
      let count = 0;

      for (let i = 0; i < promises.length; i++) {
        MyPromise.resolve(promises[i]).then(
          value => {
            results[i] = { status: 'fulfilled', value };
            count++;
            if (count === promises.length) {
              resolve(results);
            }
          },
          reason => {
            results[i] = { status: 'rejected', reason };
            count++;
            if (count === promises.length) {
              resolve(results);
            }
          }
        );
      }
    });
  }

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

      for (let i = 0; i < promises.length; i++) {
        MyPromise.resolve(promises[i]).then(
          value => {
            resolve(value);
          },
          reason => {
            errors[i] = reason;
            count++;
            if (count === promises.length) {
              reject(new AggregateError(errors, 'All promises were rejected'));
            }
          }
        );
      }
    });
  }
}

使用示例

基本使用

javascript
// 创建一个Promise
const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功');
  }, 1000);
});

// 处理成功
promise.then(value => {
  console.log(value); // 输出: 成功
});

错误处理

javascript
// 创建一个Promise
const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject('失败');
  }, 1000);
});

// 处理失败
promise.catch(reason => {
  console.log(reason); // 输出: 失败
});

链式调用

javascript
// 创建一个Promise
const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(1);
  }, 1000);
});

// 链式调用
promise
  .then(value => {
    console.log(value); // 输出: 1
    return value + 1;
  })
  .then(value => {
    console.log(value); // 输出: 2
    return value + 1;
  })
  .then(value => {
    console.log(value); // 输出: 3
  });

Promise.all

javascript
// 创建多个Promise
const promise1 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve('Promise 1');
  }, 1000);
});

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

const promise3 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve('Promise 3');
  }, 1500);
});

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

Promise.race

javascript
// 创建多个Promise
const promise1 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve('Promise 1');
  }, 1000);
});

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

const promise3 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve('Promise 3');
  }, 1500);
});

// 使用Promise.race
MyPromise.race([promise1, promise2, promise3]).then(value => {
  console.log(value); // 输出: 'Promise 2'
});

Promise.allSettled

javascript
// 创建多个Promise
const promise1 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve('Promise 1');
  }, 1000);
});

const promise2 = new MyPromise((_, reject) => {
  setTimeout(() => {
    reject('Promise 2 failed');
  }, 500);
});

const promise3 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve('Promise 3');
  }, 1500);
});

// 使用Promise.allSettled
MyPromise.allSettled([promise1, promise2, promise3]).then(results => {
  console.log(results);
  /* 输出:
  [
    { status: 'fulfilled', value: 'Promise 1' },
    { status: 'rejected', reason: 'Promise 2 failed' },
    { status: 'fulfilled', value: 'Promise 3' }
  ]
  */
});

Promise.any

javascript
// 创建多个Promise
const promise1 = new MyPromise((_, reject) => {
  setTimeout(() => {
    reject('Promise 1 failed');
  }, 1000);
});

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

const promise3 = new MyPromise((_, reject) => {
  setTimeout(() => {
    reject('Promise 3 failed');
  }, 1500);
});

// 使用Promise.any
MyPromise.any([promise1, promise2, promise3]).then(value => {
  console.log(value); // 输出: 'Promise 2'
});

面试常见问题

1. 什么是Promise?它的状态有哪些?

答案示例: Promise是JavaScript中处理异步操作的重要概念,它代表了一个异步操作的最终完成(或失败)及其结果值。Promise有三种状态:

  • pending:初始状态,既不是成功,也不是失败状态
  • fulfilled:操作成功完成
  • rejected:操作失败

Promise的状态一旦改变,就不会再变。

2. 如何实现一个Promise?

答案示例: 实现一个Promise需要以下几个核心部分:

  1. 状态管理:管理Promise的三种状态(pending、fulfilled、rejected)
  2. 回调队列:存储then和catch方法注册的回调函数
  3. 异步处理:使用setTimeout等异步方法确保回调函数在Promise状态改变后执行
  4. 链式调用:then方法返回一个新的Promise,支持链式调用
  5. 错误捕获:catch方法用于捕获错误
  6. 静态方法:实现resolve、reject、all、race等静态方法

具体实现代码可以参考上面的基础版本。

3. Promise.all和Promise.race的区别是什么?

答案示例: Promise.all和Promise.race都是Promise的静态方法,它们的区别在于:

  • Promise.all:接收一个Promise数组,返回一个新的Promise,当所有Promise都成功时,返回的Promise才会成功,结果是所有Promise的结果组成的数组;当任何一个Promise失败时,返回的Promise就会失败,失败原因是第一个失败的Promise的原因。
  • Promise.race:接收一个Promise数组,返回一个新的Promise,当任何一个Promise完成(成功或失败)时,返回的Promise就会完成,结果是第一个完成的Promise的结果。

4. 如何处理Promise的错误?

答案示例: 处理Promise的错误有以下几种方法:

  1. 使用catch方法:Promise的catch方法可以捕获前面所有Promise的错误。
javascript
promise
  .then(value => {
    console.log(value);
  })
  .catch(reason => {
    console.log(reason);
  });
  1. 在then方法中处理错误:then方法的第二个参数可以处理错误。
javascript
promise.then(
  value => {
    console.log(value);
  },
  reason => {
    console.log(reason);
  }
);
  1. 使用try-catch:在async函数中,可以使用try-catch捕获Promise的错误。
javascript
async function handlePromise() {
  try {
    const value = await promise;
    console.log(value);
  } catch (error) {
    console.log(error);
  }
}

5. Promise的链式调用是如何实现的?

答案示例: Promise的链式调用是通过then方法返回一个新的Promise实现的。具体来说:

  1. 当调用Promise的then方法时,它会返回一个新的Promise对象
  2. 这个新的Promise对象的状态由then方法中回调函数的返回值决定
  3. 如果回调函数返回一个值,新的Promise会以该值为结果变为fulfilled状态
  4. 如果回调函数抛出一个错误,新的Promise会以该错误为原因变为rejected状态
  5. 如果回调函数返回一个Promise,新的Promise会等待该Promise完成,然后以相同的结果或错误改变状态

这种机制使得Promise可以通过链式调用的方式处理一系列异步操作,避免了回调地狱。

总结

Promise是JavaScript中处理异步操作的重要概念,它提供了一种优雅的方式来处理异步代码,避免了回调地狱。Promise有三种状态:pending、fulfilled和rejected,状态一旦改变,就不会再变。

实现一个Promise需要管理状态、存储回调队列、处理异步操作、支持链式调用和错误捕获。通过学习Promise的实现原理,我们可以更好地理解和使用Promise,提高异步代码的质量和可维护性。

Promise的静态方法(如Promise.all、Promise.race、Promise.allSettled、Promise.any)提供了处理多个Promise的便捷方式,可以根据不同的场景选择合适的方法。

通过学习和使用Promise,你将能够更好地处理异步操作,写出更加优雅和可维护的JavaScript代码,为面试和工作做好准备。

好好学习,天天向上