1. 方案设计
function asyncTaskControl(tasks, maxConcurrent) {
return new Promise((resolve, reject) => {
const results = [];
let completedCount = 0;
const taskQueue = [...tasks];
const executeTask = () => {
if (taskQueue.length === 0 && completedCount === tasks.length) {
resolve(results);
return;
}
if (taskQueue.length === 0) return;
const task = taskQueue.shift();
Promise.resolve(task())
.then(result => {
results.push({ status: 'fulfilled', value: result });
})
.catch(error => {
results.push({ status:'rejected', reason: error });
})
.finally(() => {
completedCount++;
executeTask();
});
};
for (let i = 0; i < Math.min(maxConcurrent, tasks.length); i++) {
executeTask();
}
});
}
// 使用示例
const tasks = [
() => new Promise(resolve => setTimeout(() => resolve('Task 1'), 1000)),
() => new Promise(resolve => setTimeout(() => resolve('Task 2'), 2000)),
() => new Promise(resolve => setTimeout(() => resolve('Task 3'), 1500)),
() => new Promise(resolve => setTimeout(() => resolve('Task 4'), 3000)),
() => new Promise(resolve => setTimeout(() => resolve('Task 5'), 2500))
];
const maxConcurrent = 3;
asyncTaskControl(tasks, maxConcurrent)
.then(results => {
console.log(results);
})
.catch(error => {
console.error(error);
});
2. 箭头函数闭包特性对内存管理的影响及避免内存泄漏的方法
影响
- 引用导致内存驻留:箭头函数的闭包会捕获其定义时所在作用域的变量。如果这些变量引用了较大的对象或 DOM 元素等资源,即使这些资源在逻辑上不再需要,由于闭包的存在,它们依然无法被垃圾回收机制回收,从而导致内存占用持续存在,可能引发内存泄漏。
- 循环引用风险:在复杂的异步场景中,如果闭包中的变量与其他对象形成循环引用,例如在一个对象的方法中使用箭头函数,箭头函数的闭包又引用了该对象本身,垃圾回收机制难以检测和回收这些循环引用的对象,也会造成内存泄漏。
避免内存泄漏的方法
- 及时释放引用:在不需要闭包捕获的变量时,手动将其设置为
null
,这样垃圾回收机制可以回收相关资源。例如,如果在一个函数中定义了箭头函数,且箭头函数捕获了某个局部变量,当该局部变量不再需要时,将其赋值为 null
。
- 使用弱引用:对于一些只希望在对象存活时引用,但又不想阻止其被垃圾回收的情况,可以使用
WeakMap
或 WeakSet
。它们的键或值是弱引用,不会阻止对象被垃圾回收,从而避免因闭包导致的内存泄漏。
- 合理设计作用域:尽量减少箭头函数闭包捕获不必要的变量,将变量的作用域限制在最小范围。避免在箭头函数中引用全局变量或长时间存活的对象,以降低闭包对内存管理的负面影响。