JavaScript异步与Promise

2026-03-17

JavaScript 异步与 Promise 笔记


1. JavaScript 异步机制概览

1.1 执行栈与事件循环

  • JS 是单线程执行
  • 执行栈(Call Stack):存储同步任务
  • 任务队列(Task Queue / Microtask Queue)
    • 宏任务(Macro Task):setTimeout、setInterval、I/O、UI 渲染
    • 微任务(Micro Task):Promise.then/catch/finally、MutationObserver
  • 事件循环(Event Loop)
    1. 执行同步任务直到栈空
    2. 执行微任务队列
    3. 执行宏任务队列
    4. 重复循环

1.2 异步类型示意

类型 示例 队列类型
微任务 Promise.then, MutationObserver Microtask
宏任务 setTimeout, setInterval, I/O Macrotask
1
2
3
4
5
6
7
8
9
10
console.log('script start');

setTimeout(() => console.log('setTimeout'), 0);

Promise.resolve().then(() => console.log('promise1'))
.then(() => console.log('promise2'));

console.log('script end');

// 输出顺序:script start -> script end -> promise1 -> promise2 -> setTimeout

2. Promise 基础与用法

2.1 创建 Promise

1
2
3
4
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => resolve('success'), 1000);
});

2.2 Promise 状态

  • Pending:初始状态
  • Fulfilled:成功
  • Rejected:失败

状态只能从 Pending 变为 Fulfilled 或 Rejected,且不可逆

2.3 Promise 用法

1
2
3
4
promise
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(() => console.log('done'));

2.4 Promise 链式调用

1
2
3
4
5
6
Promise.resolve(1)
.then(val => val + 1)
.then(val => { console.log(val); return val + 1; })
.then(val => console.log(val));

// 输出:2 -> 3

2.5 Promise.all / allSettled / race / any

1
2
3
4
5
6
7
8
9
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.reject('error');

Promise.all([p1, p2]).then(console.log); // [1,2]
Promise.allSettled([p1, p3]).then(console.log);
// [{status:'fulfilled', value:1}, {status:'rejected', reason:'error'}]
Promise.race([p1, p2]).then(console.log); // 1
Promise.any([p3, p2]).then(console.log); // 2

3. async / await 高阶用法

3.1 基本语法

1
2
3
4
async function fetchData() {
const result = await promise;
console.log(result);
}

3.2 错误处理

1
2
3
4
5
6
7
8
9
async function test() {
try {
await Promise.reject('error');
} catch (err) {
console.error(err);
} finally {
console.log('finally');
}
}

3.3 并发与串行

  • 串行(等待前一个完成再执行下一个)
1
2
const result1 = await asyncFunc1();
const result2 = await asyncFunc2(result1);
  • 并发(同时发起请求,等待全部完成)
1
const [result1, result2] = await Promise.all([asyncFunc1(), asyncFunc2()]);

4. 底层原理与微任务机制

4.1 Promise.then 微任务原理

  • then/catch/finally 会在微任务队列中注册回调
  • 微任务优先于宏任务执行
1
2
3
4
5
6
7
8
9
console.log(1);

setTimeout(() => console.log(2), 0);

Promise.resolve().then(() => console.log(3));

console.log(4);

// 输出顺序:1 -> 4 -> 3 -> 2

4.2 Promise 内部执行流程

  1. 创建 Promise,状态 Pending
  2. then 注册回调函数到微任务队列
  3. resolve/reject 改变状态,异步执行注册回调

4.3 async/await 本质

  • async 函数返回 Promise
  • await 后面跟 Promise,本质是 Promise.then(...)
  • 可以理解为语法糖,更直观处理异步逻辑

5. 常见异步陷阱

  1. 忘记 return promise 链
1
2
// ❌
promise.then(val => { val + 1 });
  1. 在 forEach 中使用 await
1
2
3
arr.forEach(async item => {
await doSomething(item); // 异步不会等待 forEach 完成
});
  • 推荐使用 for...ofmap + Promise.all
  1. Promise 内抛异常未捕获
1
2
3
new Promise((resolve, reject) => { throw new Error('err'); })
.then(() => console.log('ok'));
// 会触发全局 unhandledrejection

6. 高级优化策略

  1. 批量异步请求
1
const results = await Promise.all(requests.map(req => fetch(req)));
  1. 并发限制
1
2
3
4
5
6
7
8
9
10
11
12
async function limitConcurrent(tasks, limit) {
const results = [];
const executing = [];
for (const task of tasks) {
const p = task();
results.push(p);
const e = p.finally(() => executing.splice(executing.indexOf(e),1));
executing.push(e);
if (executing.length >= limit) await Promise.race(executing);
}
return Promise.all(results);
}
  1. 取消异步请求
  • 使用 AbortController 或第三方库(axios cancel token)

7. 面试要点

  • 异步队列与事件循环原理
  • Promise 状态与链式调用
  • async/await 与 Promise 的关系
  • 微任务与宏任务区别
  • 并发控制与错误处理
  • 常见坑:forEach + await、未 return Promise、异常未捕获