今天在练习高并发任务,发现我对于Promise的执行时机有所误解,需求是构建一个任务数组用于后续按需执行。
问题代码
js
const mockUserDataTask = (id) =>
new Promise((resolve) =>{
console.log(`用户数据 ${id} 加载中`),
setTimeout(() => resolve(`用户数据 ${id} 加载完成`), 3000)
});
const test = [
{ id: "task-1", func: mockUserDataTask(1) },
{ id: "task-2", func: mockUserDataTask(2) },
{ id: "task-3", func: mockUserDataTask(3) },
{ id: "task-4", func: mockUserDataTask(4) },
];
test[0].func.then((res) => {
console.log(res);
test[2].func.then((res) => {
console.log(res);
});
});
test[1].func.then((res) => {
console.log(res);
test[3].func.then((res) => {
console.log(res);
});
});
预期执行顺序:
先启动任务1和任务2,完成后启动任务3和任务4
实际执行顺序:
所有4个任务同时启动
为什么会同步加载4个Promise 对象?
Promise 对象在创建时会立即执行。
💡 这是因为Promise的构造函数部分是同步执行的,传入的 executor 函数会立即调用;而resolve/reject回调的(.then()/.catch())是异步的属于Microtask(微任务)
- 当我直接调用
mockUserDataTask(id)
时,Promise 构造函数会立即执行 - 这意味着我在创建
test
数组时,4个 Promise 已经同时开始执行(包括它们的setTimeout
) - 所以会立即看到所有4个"加载中"
采用闭包的方式解决这一问题:
- 外层函数返回的是一个新的函数,而不是直接返回Promise
- 只有在调用
func()
时才会创建并执行Promise
正确写法
// ❌ Promise立即执行 const task = new Promise(executor);
// ✅ 延迟执行(闭包) const createTask = () => new Promise(executor);
js
//使用闭包有效解决
const mockUserDataTask = (id) => () => new Promise((resolve) => {
console.log(`用户数据 ${id} 加载中`)
setTimeout(() => {
console.log('执行了')
resolve(`用户数据 ${id} 加载完成`)
}, 3000)
});
test[0].func().then((res) => {
console.log(res);
test[2].func().then((res) => {
console.log(res);
});
});