MST

星途 面试题库

面试题:JavaScript数组并发迭代中如何控制并发数量

给定一个包含大量异步任务的数组(例如需要通过`fetch`获取大量URL的数据),由于系统资源限制,你需要控制并发执行的任务数量为`n`(假设`n = 5`),即同一时间最多只能有5个任务在执行。当有任务完成时,立即从任务数组中取出下一个任务执行,直到所有任务完成。请使用`async/await`和`Promise`实现此功能,并确保错误处理得当。
21.5万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试
function asyncTask(url) {
    return new Promise((resolve, reject) => {
        // 模拟异步操作,这里以fetch为例
        fetch(url)
           .then(response => {
                if (!response.ok) {
                    throw new Error('Network response was not ok');
                }
                return response.json();
            })
           .then(data => resolve(data))
           .catch(error => reject(error));
    });
}

async function executeTasks(tasks, concurrency) {
    const results = [];
    const runningTasks = [];

    for (let i = 0; i < concurrency; i++) {
        const task = tasks.shift();
        if (task) {
            const promise = asyncTask(task);
            runningTasks.push(promise);
            promise
               .then(result => {
                    results.push(result);
                    const nextTask = tasks.shift();
                    if (nextTask) {
                        const newPromise = asyncTask(nextTask);
                        runningTasks.push(newPromise);
                        newPromise
                           .then(nextResult => results.push(nextResult))
                           .catch(error => results.push({ error }))
                           .finally(() => runningTasks.splice(runningTasks.indexOf(newPromise), 1));
                    }
                })
               .catch(error => results.push({ error }))
               .finally(() => runningTasks.splice(runningTasks.indexOf(promise), 1));
        }
    }

    while (runningTasks.length > 0) {
        await Promise.race(runningTasks);
    }

    return results;
}

// 示例任务数组
const taskUrls = [
    'url1',
    'url2',
    'url3',
    'url4',
    'url5',
    'url6',
    'url7',
    'url8',
    'url9',
    'url10'
];

executeTasks(taskUrls, 5)
   .then(finalResults => {
        console.log(finalResults);
    })
   .catch(error => {
        console.error('Overall error:', error);
    });
  1. asyncTask函数
    • 此函数接受一个url参数,返回一个Promise
    • 这里通过fetch模拟异步获取数据的操作,处理响应并返回解析后的数据,如果请求失败则reject
  2. executeTasks函数
    • tasks参数是包含所有任务(这里是URL)的数组,concurrency参数表示最大并发数。
    • results数组用于存储所有任务的执行结果,runningTasks数组用于跟踪当前正在运行的任务。
    • 首先,循环启动concurrency数量的任务,并将其添加到runningTasks数组中。每个任务完成后,从tasks数组中取出下一个任务并启动,同时处理任务执行过程中的成功和失败情况。
    • 使用while循环和Promise.race等待所有正在运行的任务完成,Promise.race会在任何一个Promise完成(无论成功或失败)时返回。
  3. 示例使用
    • 定义一个包含多个URL的taskUrls数组。
    • 调用executeTasks函数,传入taskUrls和最大并发数5,并处理最终的结果或错误。

这样就实现了在最大并发数限制下,顺序执行所有异步任务并处理错误的功能。