Promise 是 JavaScript 异步编程的核心解决方案,也是前端工程师进阶必备的核心知识点。本文将全方位介绍 Promise,涵盖从基础概念到高级应用,再到面试实战的全链路知识。


一、Promises/A+ 规范基础

1. Promise 的状态

Promise 是一个​​状态机​​,有且仅有三种状态:

  • ​pending(等待中)​​:初始状态,既不是成功也不是失败。
  • ​fulfilled(已成功)​​:操作成功完成,通过 resolve()触发。
  • ​rejected(已失败)​​:操作失败,通过 reject()触发。

🎯 ​​状态不可逆​​:一旦从 pending 变为 fulfilled 或 rejected,状态将永久固定,不可再次改变。


2. then 方法:核心机制

then是 Promise 的核心方法,用于注册状态变更后的回调函数:

  • ​接收两个回调​​:
    • 第一个参数:onFulfilled(状态变为 fulfilled 时执行)。
    • 第二个参数:onRejected(状态变为 rejected 时执行,可选)。
  • ​回调返回值​
    • 若回调返回普通值(非 Promise),则新 Promise 以该值 fulfilled。

    • 若回调抛出异常,则新 Promise 以该异常 rejected。
    • 若回调返回另一个 Promise,则当前 Promise 会​​跟随该返回 Promise 的状态​​(链式调用的核心)。
const p = new Promise((resolve) => resolve(10));

p.then(
  (value) => {
    console.log(value); // 10(onFulfilled 回调)
    return value * 2;   // 返回普通值 → 新 Promise 以 20 fulfilled
  },
  (err) => console.error(err) // 不会执行(原 Promise 未失败)
).then((newValue) => {
  console.log(newValue); // 20(跟随返回的隐式 Promise)
});

3. Promise 解析过程(核心机制)

当 then的回调返回一个 ​​新的 Promise(记作 P)​​ 时,当前 Promise 会暂停自身的状态变更,转而​​监听 P 的状态​​:

  • 若 P 变为 fulfilled,则当前 Promise 以 P 的结果 fulfilled;
  • 若 P 变为 rejected,则当前 Promise 以 P 的错误 rejected。

🎯 ​​链式调用的本质​​:通过解析过程实现多个异步操作的依次执行(前一个操作的结果作为下一个操作的输入)。


二、传统异步任务处理的痛点

1. 回调函数模式

早期 JavaScript 通过嵌套回调处理异步(例如 AJAX 请求):

getData(function(result1) {
  processResult1(result1, function(result2) {
    saveResult2(result2, function(result3) {
      // 嵌套层级加深 → 代码难以维护
    });
  });
});

2. 回调地狱(Callback Hell)

多层嵌套回调会导致代码横向扩展(缩进层级过深),出现“金字塔”结构的代码,可读性差、错误处理困难、难以复用逻辑。

🎯 ​​Promise 的诞生​​:为了解决回调地狱问题,提供更扁平化的异步代码组织方式。


三、Promise 详解

1. 什么是 Promise?

  • ​本质​​:一个构造函数(类),通过 new Promise(executor)实例化。
  • 核心机制​​:
    • executor 是一个同步执行的回调函数,接收两个参数:resolve(标记成功)和 reject(标记失败)。
    • Promise 内部通过状态机管理异步操作的结果,外部通过 then/catch/finally监听状态变更。
const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('异步操作成功'), 1000); // 1秒后标记成功
});

2. resolve 的参数规则

resolve可接受多种类型的参数,处理逻辑不同:

参数类型

行为

普通值(如字符串、数字)

当前 Promise 以该值 fulfilled。

另一个 Promise

当前 Promise 会跟随该 Promise 的状态(链式调用的基础)。

Thenable 对象(含 then 方法的对象)

会尝试调用其 then 方法,将其转换为标准 Promise 行为。

// 示例 1:普通值
Promise.resolve(42).then(v => console.log(v)); // 42

// 示例 2:返回另一个 Promise
Promise.resolve(Promise.resolve('嵌套 Promise')).then(v => console.log(v)); // 嵌套 Promise

// 示例 3:Thenable 对象
const thenable = { then(resolve) { resolve('Thenable 转换成功'); } };
Promise.resolve(thenable).then(v => console.log(v)); // Thenable 转换成功

3. Promise 的实例方法

(1) then 方法
  • ​参数​​:onFulfilled(成功回调,可选)、onRejected(失败回调,可选)。
  • ​返回值​​:一个新的 Promise(支持链式调用)。
  • ​回调返回值​​:决定新 Promise 的状态(如返回普通值、Promise 或抛出异常)。
Promise.resolve(1)
  .then(val => val + 1) // 返回普通值 2 → 新 Promise 以 2 fulfilled
  .then(val => console.log(val)); // 2
(2) 多次调用 then
  • 每次调用 then都会注册新的回调,​​按注册顺序依次执行​​(即使前一个回调异步延迟)。
  • 多个 then可以分别处理同一 Promise 的成功状态。
const p = Promise.resolve(10);
p.then(v => console.log(v)); // 10
p.then(v => console.log(v + 5)); // 15
(3) catch 方法
  • ​作用​​:专门捕获 Promise 链中的错误(相当于 then(null, onRejected))。
  • ​参数​​:错误处理回调(接收错误对象)。
  • ​特性​​:可捕获当前 Promise 或链中上游未处理的 rejected 状态。
Promise.reject(new Error('操作失败'))
  .catch(err => console.error('捕获错误:', err.message)); // 捕获错误: 操作失败
(4) finally 方法
  • ​作用​​:无论 Promise 成功或失败,都会执行的清理逻辑(如关闭加载动画)。
  • ​参数​​:无参数回调(无法获取 Promise 的结果或错误)。
  • ​特性​​:不会改变原 Promise 的状态或结果。
Promise.resolve('成功')
  .finally(() => console.log('无论如何都会执行')) // 无论如何都会执行
  .then(v => console.log(v)); // 成功

4. Promise 的类方法

(1) Promise.resolve / Promise.reject
  • ​作用​​:快速创建已 resolved/rejected 的 Promise。
  • ​参数​​:与 resolve/reject方法一致。
Promise.resolve('直接成功').then(v => console.log(v)); // 直接成功
Promise.reject('直接失败').catch(e => console.error(e)); // 直接失败
(2) Promise.all
  • ​作用​​:并行执行多个 Promise,​​全部成功时返回结果数组​​,​​任一失败立即 rejected​​。
  • ​参数​​:Promise 数组。
  • 适用场景​​:同时发起多个独立异步请求,需全部完成后再处理结果。
Promise.all([
  Promise.resolve(1),
  Promise.resolve(2),
]).then(([res1, res2]) => console.log(res1, res2)); // 1 2

Promise.all([
  Promise.resolve(1),
  Promise.reject('失败'),
]).catch(e => console.error(e)); // 失败
(3) Promise.allSettled
  • 作用​​:并行执行多个 Promise,​​等待所有完成(无论成功/失败)​​,返回每个 Promise 的状态和结果。
  • ​参数​​:Promise 数组。
  • ​适用场景​​:需要知道所有异步操作的最终状态(如批量提交后统计成功/失败数量)。
Promise.allSettled([
  Promise.resolve(1),
  Promise.reject('失败'),
]).then(results => {
  results.forEach(r => console.log(r.status, r.value || r.reason));
  // fulfilled 1
  // rejected 失败
});
(4) Promise.race
  • ​作用​​:并行执行多个 Promise,​​返回第一个 settled(成功/失败)的 Promise 结果​​。
  • ​参数​​:Promise 数组。
  • 适用场景​​:超时控制(如请求超时后取消操作)。
Promise.race([
  Promise.resolve('快的'),
  new Promise(resolve => setTimeout(() => resolve('慢的'), 1000)),
]).then(v => console.log(v)); // 快的
(5) Promise.any
  • ​作用​​:并行执行多个 Promise,​​返回第一个成功的 Promise 结果​​,​​全部失败时抛出 AggregateError​​。
  • ​参数​​:Promise 数组。
  • ​适用场景​​:多备用数据源(如主接口失败后尝试备用接口)。
Promise.any([
  Promise.reject('失败1'),
  Promise.resolve('成功'),
]).then(v => console.log(v)); // 成功

四、手写 Promise 实现(核心逻辑)

手写 Promise 是深入理解其原理的最佳方式,需实现以下核心方法(可通过 Jest 编写单元测试验证):

  • ​构造函数(constructor)​​:接收 executor,管理状态和结果。
  • ​then/catch/finally​​:注册回调并处理链式调用。
  • 类方法(resolve/reject/all/allSettled/race/any)​​:静态工具方法。

🎯 ​​关键点​​:状态不可逆、then 的链式调用(返回新 Promise)、异步执行回调(通过微任务队列,如 queueMicrotask)。


下面是一个完整的手写 Promise 实现(支持 Promises/A+ 规范),包含核心方法(constructorthencatchfinally)及静态方法(resolverejectallallSettledraceany),并附带对应的 Jest 单元测试代码。

1.Promise 实现 (myPromise.js)

// 定义 Promise 的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

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

    // 定义 resolve 函数
    const resolve = (value) => {
      // 只有 pending 状态可以改变
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.value = value;
        // 执行所有成功的回调
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };

    // 定义 reject 函数
    const reject = (reason) => {
      // 只有 pending 状态可以改变
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.reason = reason;
        // 执行所有失败的回调
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };

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

  // then 方法
  then(onFulfilled, onRejected) {
    // 处理 then 的参数不是函数的情况
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };

    // 返回一个新的 Promise 以实现链式调用
    const promise2 = new MyPromise((resolve, reject) => {
      // 如果状态是 fulfilled
      if (this.state === FULFILLED) {
        // 使用 setTimeout 模拟微任务
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            // 解析 promise2 和 x 的关系
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.state === REJECTED) {
        // 如果状态是 rejected
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            // 解析 promise2 和 x 的关系
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.state === PENDING) {
        // 如果状态是 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;
  }

  // 解析 promise 和 x 的关系
  resolvePromise(promise2, x, resolve, reject) {
    // 如果 promise2 和 x 是同一个对象,抛出 TypeError
    if (promise2 === x) {
      return reject(new TypeError('Chaining cycle detected for promise'));
    }

    // 如果 x 是一个 Promise
    if (x instanceof MyPromise) {
      x.then(resolve, reject);
    } else {
      // 如果 x 是一个普通值
      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) {
    // 如果 value 是一个 Promise,直接返回
    if (value instanceof MyPromise) {
      return value;
    }
    // 否则返回一个新的 resolved Promise
    return new MyPromise(resolve => resolve(value));
  }

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

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

      if (promiseCount === 0) {
        resolve(results);
        return;
      }

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          value => {
            results[index] = value;
            completed++;
            if (completed === promiseCount) {
              resolve(results);
            }
          },
          reason => {
            reject(reason);
          }
        );
      });
    });
  }

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

      if (promiseCount === 0) {
        resolve(results);
        return;
      }

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          value => {
            results[index] = { status: FULFILLED, value };
            completed++;
            if (completed === promiseCount) {
              resolve(results);
            }
          },
          reason => {
            results[index] = { status: REJECTED, reason };
            completed++;
            if (completed === promiseCount) {
              resolve(results);
            }
          }
        );
      });
    });
  }

  // 静态 race 方法
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach(promise => {
        MyPromise.resolve(promise).then(resolve, reject);
      });
    });
  }

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

      if (promiseCount === 0) {
        reject(new AggregateError(errors, 'All promises were rejected'));
        return;
      }

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          value => {
            resolve(value);
          },
          reason => {
            errors[index] = reason;
            rejectedCount++;
            if (rejectedCount === promiseCount) {
              reject(new AggregateError(errors, 'All promises were rejected'));
            }
          }
        );
      });
    });
  }
}

module.exports = MyPromise;

2.Jest 单元测试 (myPromise.test.js)

const MyPromise = require('./myPromise');

describe('MyPromise', () => {
  // 测试构造函数和基本功能
  describe('Constructor', () => {
    test('should execute executor immediately', () => {
      let executed = false;
      new MyPromise(() => {
        executed = true;
      });
      expect(executed).toBe(true);
    });

    test('should handle resolve in executor', (done) => {
      new MyPromise((resolve) => {
        resolve('success');
      }).then((value) => {
        expect(value).toBe('success');
        done();
      });
    });

    test('should handle reject in executor', (done) => {
      new MyPromise((_, reject) => {
        reject('error');
      }).catch((reason) => {
        expect(reason).toBe('error');
        done();
      });
    });

    test('should catch executor errors', (done) => {
      new MyPromise(() => {
        throw new Error('executor error');
      }).catch((error) => {
        expect(error.message).toBe('executor error');
        done();
      });
    });
  });

  // 测试 then 方法
  describe('then', () => {
    test('should handle fulfilled promise', (done) => {
      new MyPromise((resolve) => {
        resolve('fulfilled');
      }).then((value) => {
        expect(value).toBe('fulfilled');
        done();
      });
    });

    test('should handle rejected promise', (done) => {
      new MyPromise((_, reject) => {
        reject('rejected');
      }).then(null, (reason) => {
        expect(reason).toBe('rejected');
        done();
      });
    });

    test('should chain then calls', (done) => {
      new MyPromise((resolve) => {
        resolve(1);
      })
        .then((value) => {
          expect(value).toBe(1);
          return value + 1;
        })
        .then((value) => {
          expect(value).toBe(2);
          return value + 1;
        })
        .then((value) => {
          expect(value).toBe(3);
          done();
        });
    });

    test('should handle async then callbacks', (done) => {
      let first = false;
      new MyPromise((resolve) => {
        resolve(1);
      })
        .then((value) => {
          first = true;
          return value + 1;
        })
        .then((value) => {
          expect(first).toBe(true);
          expect(value).toBe(2);
          done();
        });
    });

    test('should use default onFulfilled if not a function', (done) => {
      new MyPromise((resolve) => {
        resolve(1);
      }).then(null).then((value) => {
        expect(value).toBe(1);
        done();
      });
    });

    test('should use default onRejected if not a function', (done) => {
      new MyPromise((_, reject) => {
        reject(1);
      }).then(null, null).catch((reason) => {
        expect(reason).toBe(1);
        done();
      });
    });
  });

  // 测试 catch 方法
  describe('catch', () => {
    test('should catch rejected promise', (done) => {
      new MyPromise((_, reject) => {
        reject('error');
      }).catch((reason) => {
        expect(reason).toBe('error');
        done();
      });
    });

    test('should chain catch calls', (done) => {
      new MyPromise((_, reject) => {
        reject('first error');
      })
        .catch((reason) => {
          expect(reason).toBe('first error');
          return 'recovered';
        })
        .then((value) => {
          expect(value).toBe('recovered');
          done();
        });
    });
  });

  // 测试 finally 方法
  describe('finally', () => {
    test('should execute finally callback', (done) => {
      let called = false;
      new MyPromise((resolve) => {
        resolve('value');
      })
        .finally(() => {
          called = true;
        })
        .then((value) => {
          expect(called).toBe(true);
          expect(value).toBe('value');
          done();
        });
    });

    test('should pass through value', (done) => {
      new MyPromise((resolve) => {
        resolve('value');
      })
        .finally(() => {})
        .then((value) => {
          expect(value).toBe('value');
          done();
        });
    });

    test('should pass through reason', (done) => {
      new MyPromise((_, reject) => {
        reject('reason');
      })
        .finally(() => {})
        .catch((reason) => {
          expect(reason).toBe('reason');
          done();
        });
    });

    test('should handle finally callback with return value', (done) => {
      new MyPromise((resolve) => {
        resolve(1);
      })
        .finally(() => {
          return 2;
        })
        .then((value) => {
          expect(value).toBe(1);
          done();
        });
    });

    test('should handle finally callback with promise', (done) => {
      new MyPromise((resolve) => {
        resolve(1);
      })
        .finally(() => {
          return new MyPromise((resolve) => {
            resolve(2);
          });
        })
        .then((value) => {
          expect(value).toBe(1);
          done();
        });
    });
  });

  // 测试静态方法 resolve
  describe('static resolve', () => {
    test('should resolve with a value', (done) => {
      MyPromise.resolve('value').then((value) => {
        expect(value).toBe('value');
        done();
      });
    });

    test('should resolve with a promise', (done) => {
      const p = new MyPromise((resolve) => {
        resolve('promise value');
      });
      MyPromise.resolve(p).then((value) => {
        expect(value).toBe('promise value');
        done();
      });
    });
  });

  // 测试静态方法 reject
  describe('static reject', () => {
    test('should reject with a reason', (done) => {
      MyPromise.reject('reason').catch((reason) => {
        expect(reason).toBe('reason');
        done();
      });
    });
  });

  // 测试静态方法 all
  describe('static all', () => {
    test('should resolve with an array of values', (done) => {
      const p1 = MyPromise.resolve(1);
      const p2 = MyPromise.resolve(2);
      const p3 = MyPromise.resolve(3);

      MyPromise.all([p1, p2, p3]).then((values) => {
        expect(values).toEqual([1, 2, 3]);
        done();
      });
    });

    test('should reject if any promise rejects', (done) => {
      const p1 = MyPromise.resolve(1);
      const p2 = MyPromise.reject('error');
      const p3 = MyPromise.resolve(3);

      MyPromise.all([p1, p2, p3]).catch((reason) => {
        expect(reason).toBe('error');
        done();
      });
    });

    test('should resolve with empty array', (done) => {
      MyPromise.all([]).then((values) => {
        expect(values).toEqual([]);
        done();
      });
    });
  });

  // 测试静态方法 allSettled
  describe('static allSettled', () => {
    test('should resolve with all settled results', (done) => {
      const p1 = MyPromise.resolve(1);
      const p2 = MyPromise.reject('error');
      const p3 = MyPromise.resolve(3);

      MyPromise.allSettled([p1, p2, p3]).then((results) => {
        expect(results).toEqual([
          { status: 'fulfilled', value: 1 },
          { status: 'rejected', reason: 'error' },
          { status: 'fulfilled', value: 3 }
        ]);
        done();
      });
    });

    test('should resolve with empty array', (done) => {
      MyPromise.allSettled([]).then((results) => {
        expect(results).toEqual([]);
        done();
      });
    });
  });

  // 测试静态方法 race
  describe('static race', () => {
    test('should resolve with the first resolved promise', (done) => {
      const p1 = new MyPromise((resolve) => {
        setTimeout(() => resolve(1), 100);
      });
      const p2 = MyPromise.resolve(2);

      MyPromise.race([p1, p2]).then((value) => {
        expect(value).toBe(2);
        done();
      });
    });

    test('should reject with the first rejected promise', (done) => {
      const p1 = new MyPromise((_, reject) => {
        setTimeout(() => reject('error'), 100);
      });
      const p2 = MyPromise.reject('quick error');

      MyPromise.race([p1, p2]).catch((reason) => {
        expect(reason).toBe('quick error');
        done();
      });
    });
  });

  // 测试静态方法 any
  describe('static any', () => {
    test('should resolve with the first resolved promise', (done) => {
      const p1 = new MyPromise((resolve) => {
        setTimeout(() => resolve(1), 100);
      });
      const p2 = MyPromise.resolve(2);

      MyPromise.any([p1, p2]).then((value) => {
        expect(value).toBe(2);
        done();
      });
    });

    test('should reject with all rejected promises if all are rejected', (done) => {
      const p1 = MyPromise.reject('error1');
      const p2 = MyPromise.reject('error2');

      MyPromise.any([p1, p2]).catch((error) => {
        expect(error.errors).toEqual(['error1', 'error2']);
        expect(error.message).toBe('All promises were rejected');
        done();
      });
    });

    test('should reject with AggregateError if all are rejected', (done) => {
      const p1 = MyPromise.reject('error1');
      const p2 = MyPromise.reject('error2');

      MyPromise.any([p1, p2]).catch((error) => {
        expect(error instanceof Error).toBe(true);
        expect(error.message).toBe('All promises were rejected');
        // 注意:这里简化了 AggregateError 的实现,实际可能需要更复杂的检查
        done();
      });
    });
  });
});

使用说明

  1. 将 Promise 实现代码保存为 myPromise.js
  2. 将测试代码保存为 myPromise.test.js
  3. 确保已安装 Jest (npm install --save-dev jest)
  4. 在 package.json 中添加测试脚本:
"scripts": {
  "test": "jest"
}

      5. 运行测试:npm test

实现说明

这个 Promise 实现包含了以下特性:

  1. 基本功能​​:
    • 三种状态:pending、fulfilled、rejected
    • 构造函数接收 executor 函数
    • 异步执行回调(使用 setTimeout 模拟微任务)
  2. 实例方法​​:
    • then(): 支持链式调用,处理成功和失败情况
    • catch(): 捕获错误
    • finally(): 无论成功失败都会执行
  3. ​静态方法​​:
    • resolve(): 创建一个已解决的 Promise
    • reject(): 创建一个已拒绝的 Promise
    • all(): 所有 Promise 都成功时返回结果数组
    • allSettled(): 所有 Promise 都完成后返回结果状态数组
    • race(): 返回第一个完成的 Promise 结果
    • any(): 返回第一个成功的 Promise,或所有都失败时抛出错误

五、async/await 介绍

1. 特点

  • ​语法糖​​:基于 Promise 的语法糖,让异步代码看起来像同步代码。
  • 本质​​:async函数返回 Promise,await用于暂停执行直到 Promise 完成。

2. 用法

async function fetchData() {
  try {
    const result = await Promise.resolve('异步数据'); // 等待 Promise 完成
    console.log(result); // 异步数据
  } catch (err) {
    console.error(err);
  }
}
fetchData();

3. 适用场景

  • 需要按顺序执行多个异步操作(如先请求用户信息,再请求订单详情)。
  • 替代复杂的 Promise 链(提升代码可读性)。

4. 与 Promise 对比

特性

async/await

Promise

代码风格

类似同步代码,更直观

链式调用,需嵌套 then/catch

错误处理

使用 try/catch

使用 catch 方法

可读性

高(逻辑线性)

较低(嵌套层级深时)

底层原理

基于 Promise

JavaScript 原生异步解决方案


六、Promise 相关面试题目

1. 经典面试题:Promise 与事件循环

​题目​​:分析以下代码的输出顺序(结合宏任务与微任务):

console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');

解题思路​​:

  1. 同步代码优先执行​​:输出 1→ 4
  2. ​微任务(Promise.then)​​:在当前宏任务结束后立即执行,输出 3
  3. ​宏任务(setTimeout)​​:在下一个事件循环中执行,输出 2

​最终输出顺序​​:1 → 4 → 3 → 2


2. 事件循环(宏任务与微任务)

  • ​宏任务​​:script 整体代码、setTimeout、setInterval、I/O 操作。
  • ​微任务​​:Promise.then/catch/finally、MutationObserver、queueMicrotask。

​执行规则​​:

  1. 执行一个宏任务(如 script 代码);
  2. 执行该宏任务产生的所有微任务;
  3. 渲染页面(如有必要);
  4. 执行下一个宏任务。

3. 解题思路总结

  • Promise 状态机​​:明确 pending → fulfilled/rejected 的不可逆性。
  • ​then 的链式调用​​:每次 then 返回新 Promise,回调返回值决定新状态。
  • ​事件循环优先级​​:微任务 > 宏任务(理解这一规则可解决 80% 的异步面试题)。

通过本文的全方位解析,你已掌握 Promise 的核心原理、实战用法及面试要点。结合实际项目中的异步场景(如 API 请求、文件读取),灵活运用 Promise 和 async/await,可显著提升代码质量和开发效率! 🚀

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐