Promise 原理与用法

Promise 的状态机制、链式调用与异常处理

问题

解释 Promise 的原理、状态、链式调用与异常处理。

解答

Promise 状态

Promise 有三种状态:

  • pending:初始状态,等待中
  • fulfilled:操作成功完成
  • rejected:操作失败

状态一旦改变就不可逆,只能从 pending 变为 fulfilled 或 rejected。

const promise = new Promise((resolve, reject) => {
  // pending 状态
  setTimeout(() => {
    resolve('成功'); // 变为 fulfilled
    // reject('失败'); // 或变为 rejected
  }, 1000);
});

基本用法

const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = true;
      if (success) {
        resolve({ id: 1, name: 'Tom' });
      } else {
        reject(new Error('请求失败'));
      }
    }, 1000);
  });
};

fetchData()
  .then(data => console.log(data))
  .catch(err => console.error(err));

链式调用

then 返回新的 Promise,支持链式调用:

Promise.resolve(1)
  .then(value => {
    console.log(value); // 1
    return value + 1;   // 返回值会被包装成 Promise
  })
  .then(value => {
    console.log(value); // 2
    return Promise.resolve(value + 1); // 也可以返回 Promise
  })
  .then(value => {
    console.log(value); // 3
  });

异常处理

// 方式一:catch 捕获链上所有错误
Promise.resolve()
  .then(() => {
    throw new Error('then 中的错误');
  })
  .then(() => {
    console.log('不会执行');
  })
  .catch(err => {
    console.error(err.message); // "then 中的错误"
  });

// 方式二:then 的第二个参数(只捕获上一个 then 的错误)
Promise.reject('错误')
  .then(
    value => console.log(value),
    err => console.error(err) // "错误"
  );

手写简易 Promise

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

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

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

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

  then(onFulfilled, onRejected) {
    // 参数默认值,实现值穿透
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
    onRejected = typeof onRejected === 'function' ? onRejected : e => { throw e };

    const promise2 = new MyPromise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolve(x);
          } catch (err) {
            reject(err);
          }
        });
      }

      if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolve(x);
          } catch (err) {
            reject(err);
          }
        });
      }

      if (this.state === 'pending') {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolve(x);
            } catch (err) {
              reject(err);
            }
          });
        });
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolve(x);
            } catch (err) {
              reject(err);
            }
          });
        });
      }
    });

    return promise2;
  }

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

// 测试
new MyPromise((resolve) => {
  setTimeout(() => resolve('hello'), 100);
})
  .then(val => val + ' world')
  .then(val => console.log(val)); // "hello world"

常用静态方法

// Promise.all - 全部成功才成功
Promise.all([
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.resolve(3)
]).then(results => console.log(results)); // [1, 2, 3]

// Promise.race - 取最快的结果
Promise.race([
  new Promise(r => setTimeout(() => r('慢'), 200)),
  new Promise(r => setTimeout(() => r('快'), 100))
]).then(result => console.log(result)); // "快"

// Promise.allSettled - 等待全部完成,不管成功失败
Promise.allSettled([
  Promise.resolve(1),
  Promise.reject('err')
]).then(results => console.log(results));
// [{status: 'fulfilled', value: 1}, {status: 'rejected', reason: 'err'}]

关键点

  • Promise 有三种状态:pending、fulfilled、rejected,状态不可逆
  • then 返回新 Promise,支持链式调用
  • catch 能捕获链上所有错误,then 第二个参数只捕获上一步错误
  • 回调通过 setTimeout 实现异步执行(微任务用 queueMicrotask)
  • Promise.all 全部成功才成功,Promise.race 取最快结果