
JavaScript 中 Promise 默认立即执行,若想实现严格串行(第二个任务在第一个完成后才启动),必须在第一个 Promise 的 then 回调中动态创建并返回第二个 Promise,而非复用已创建的实例。
javascript 中 promise 默认立即执行,若想实现严格串行(第二个任务在第一个完成后才启动),必须在第一个 promise 的 `then` 回调中**动态创建并返回**第二个 promise,而非复用已创建的实例。
在你的原始代码中,task1 和 task2 都在声明时就已同步创建并启动——即两个 setTimeout 同时计时,各自 5 秒后 resolve。因此无论你用 .then(Promise.resolve(task2)) 还是 await task2,task2 实际早已运行中,其结果自然在第 5 秒就绪,导致日志“看似提前”输出。
关键误区在于:Promise 是“执行器(executor)”一创建就立即运行的异步任务容器,不是延迟定义的待调度指令。 所以 const task2 = new Promise(...) 这一行执行时,计时器就已经启动了。
✅ 正确做法:将第二个 Promise 的创建逻辑延迟到第一个 Promise 解决之后,即在 .then() 回调内部 new Promise(...):
const promiseTime = 500;
const start = performance.timeOrigin + performance.now();
const task1 = new Promise((res) => {
setTimeout(() => res('one'), promiseTime);
});
task1
.then((x) => {
console.log(`${x} ${(performance.timeOrigin + performance.now()) - start}ms`);
// ✅ 动态创建 task2 —— 此时 task1 已 resolve,计时才开始
return new Promise((res) => {
setTimeout(() => res('two'), promiseTime);
});
})
.then((x) => {
console.log(`${x} ${(performance.timeOrigin + performance.now()) - start}ms`);
});
输出示例(单位:毫秒):
one 502.13ms two 1004.87ms
同样,使用 async/await 时也需遵循相同原则:
async function runSequentially() {
const start = performance.timeOrigin + performance.now();
const res1 = await new Promise((res) => {
setTimeout(() => res('one'), 500);
});
console.log(`${res1} ${(performance.timeOrigin + performance.now()) - start}ms`);
const res2 = await new Promise((res) => {
setTimeout(() => res('two'), 500);
});
console.log(`${res2} ${(performance.timeOrigin + performance.now()) - start}ms`);
}
runSequentially();
⚠️ 注意事项:
- ❌ 错误:
const p2 = new Promise(...); p1.then(() => p2)→p2已提前运行; - ✅ 正确:
p1.then(() => new Promise(...))→p2创建并启动被推迟到p1完成后; - 若需复用逻辑,可封装为工厂函数:
const makeDelayedTask = (msg, delay) => () => new Promise(r => setTimeout(() => r(msg), delay));,再在then中调用makeDelayedTask('two', 500)(); - 对于真实异步操作(如
fetch、数据库查询),只要不提前调用,天然满足串行;但定时器、Promise构造器等“热启动”行为需特别注意时机控制。
掌握这一原则,才能真正驾驭 Promise 的执行时序,避免隐式并发带来的逻辑偏差。










