
本文解释为何 await 三个独立创建的 Promise 仍表现为并行执行——根本原因在于 new Promise() 的执行器函数(executor)在构造时立即同步执行,而非等待 await 触发,因此所有 setTimeout 在 0ms 就已启动。
本文解释为何 `await` 三个独立创建的 promise 仍表现为并行执行——根本原因在于 `new promise()` 的执行器函数(executor)在构造时**立即同步执行**,而非等待 `await` 触发,因此所有 `settimeout` 在 0ms 就已启动。
在 JavaScript 中,async/await 提供了优雅的异步流程控制语法,但它并不改变 Promise 的创建时机。许多开发者误以为 await promiseX 意味着“此时才开始执行该 Promise”,但实际上:
✅ Promise 构造器中的回调(executor)是同步、立即执行的;
❌ await 只是暂停 async 函数的执行,等待该 Promise 进入 fulfilled 或 rejected 状态,而不控制其何时被创建或启动。
来看原始代码的问题本质:
const promise1 = new Promise((resolve) => {
console.log('promise1 executor started'); // ⚠️ 立即输出!
setTimeout(() => resolve(1), 5000);
});
const promise2 = new Promise((resolve) => {
console.log('promise2 executor started'); // ⚠️ 同样立即输出!
setTimeout(() => resolve(2), 5000);
});
// 三者在 runPromises() 调用前就已启动 setTimeout → 所有定时器从 t=0 并行计时
因此,尽管 await promise1、await promise2、await promise3 是串行等待,但三个 setTimeout 实际上在脚本加载完成后的同一时刻(t=0)就开始倒计时,5 秒后几乎同时 resolve → 总耗时约 5 秒,而非预期的 15 秒。
✅ 正确做法:延迟 Promise 创建(惰性求值)
若需真正串行执行(即第二个 Promise 在第一个 resolve 后才启动),应将 Promise 封装为函数,仅在 await 时调用:
const makePromise1 = () => new Promise(resolve => {
console.log('Starting promise1...');
setTimeout(() => {
console.log('promise1 resolved');
resolve(1);
}, 5000);
});
const makePromise2 = () => new Promise(resolve => {
console.log('Starting promise2...');
setTimeout(() => {
console.log('promise2 resolved');
resolve(2);
}, 5000);
});
const makePromise3 = () => new Promise(resolve => {
console.log('Starting promise3...');
setTimeout(() => {
console.log('promise3 resolved');
resolve(3);
}, 5000);
});
async function runPromises() {
const value1 = await makePromise1(); // t=0 启动,t=5s 完成
console.log(value1); // 输出 1
const value2 = await makePromise2(); // t=5s 启动,t=10s 完成
console.log(value2); // 输出 2
const value3 = await makePromise3(); // t=10s 启动,t=15s 完成
console.log(value3); // 输出 3
}
runPromises();
// 总耗时 ≈ 15 秒,符合串行预期
? 补充说明:Promise.all() 的对比
-
await Promise.all([promise1, promise2, promise3]):仍会并行执行(因 Promise 已提前创建),但等待全部完成才继续; -
await单个 Promise 函数调用(如await makePromise1()):实现真·按需启动 + 串行等待。
⚠️ 注意事项
- 不要将耗时操作直接写在
new Promise(...)外部作用域中,除非你明确希望它立即执行; - 在复杂业务逻辑中(如 API 请求、数据库查询),推荐统一使用工厂函数(如
fetchUser(id))而非预创建 Promise,以避免资源浪费和状态失控; - 可借助
Promise.allSettled()或Promise.race()等组合策略,按需平衡并发与顺序需求。
理解 Promise 的创建(creation) 与 消费(consumption) 是掌握 async/await 的关键分水岭——前者决定“何时开始”,后者决定“何时等待”。











