MST

星途 面试题库

面试题:JavaScript 异步迭代与并发控制

假设你有一组异步任务需要迭代执行,但同时要控制并发数量以避免资源耗尽,例如同时发起多个HTTP请求。请详细阐述如何使用JavaScript异步迭代结合队列、信号量等概念来实现这一需求,并给出完整的代码实现,包括对代码思路和性能优化方面的解释。
24.9万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

代码思路

  1. 队列:用于存储所有待执行的异步任务。
  2. 信号量:通过一个计数器来表示当前允许并发执行的任务数量。当任务开始执行时,信号量减1;任务完成时,信号量加1。
  3. 异步迭代:使用 asyncawait 来顺序执行任务,并在合适的时机控制并发。

代码实现

function asyncTaskQueue(tasks, concurrency) {
    return new Promise((resolve, reject) => {
        const queue = [...tasks];
        let running = 0;
        const results = [];

        function next() {
            while (running < concurrency && queue.length > 0) {
                const task = queue.shift();
                running++;
                task()
                   .then(result => {
                        results.push(result);
                        running--;
                        if (queue.length === 0 && running === 0) {
                            resolve(results);
                        } else {
                            next();
                        }
                    })
                   .catch(err => {
                        reject(err);
                    });
            }
            if (queue.length === 0 && running === 0) {
                resolve(results);
            }
        }

        next();
    });
}

// 示例使用
const asyncTasks = [
    () => new Promise(resolve => setTimeout(() => resolve('Task 1'), 1000)),
    () => new Promise(resolve => setTimeout(() => resolve('Task 2'), 1500)),
    () => new Promise(resolve => setTimeout(() => resolve('Task 3'), 500)),
    () => new Promise(resolve => setTimeout(() => resolve('Task 4'), 2000))
];

asyncTaskQueue(asyncTasks, 2)
   .then(results => {
        console.log(results);
    })
   .catch(err => {
        console.error(err);
    });

性能优化

  1. 控制并发数量:通过 concurrency 参数严格控制同时执行的任务数量,避免资源耗尽。
  2. 减少等待时间:当有任务完成时,立即从队列中取出新的任务执行,尽量减少空闲时间,提高整体效率。
  3. 错误处理:在任务执行过程中捕获错误并及时通过 reject 传递,避免任务队列出现未处理的错误而导致程序异常。