JavaScript 并发任务控制

简介: 【8月更文挑战第31天】JavaScript 并发任务控制

在JavaScript中,由于其单线程的特性,传统的并发任务处理通常依赖于异步编程模式,如回调函数、Promises、async/await等。然而,当我们需要控制多个并发任务时,比如限制同时运行的任务数量,我们可以使用Promise结合一些额外的逻辑来实现。这里,我将介绍如何使用PromiseArray.prototype.map结合一个简单的并发控制函数来限制同时运行的任务数量。

场景描述

假设我们有一个API调用列表,我们需要并发地向这些API发送请求,但出于性能或API速率限制的考虑,我们希望同时进行的请求数量不超过某个特定值(比如5个)。

解决方案

我们可以创建一个函数concurrentRequests,它接受三个参数:一个请求函数(这个函数返回一个Promise),一个请求参数数组,以及一个并发限制数。

function concurrentRequests(fn, args, concurrency) {
   
    let activeCount = 0;
    const results = [];
    const queue = [...args];

    // 辅助函数,用于执行下一个请求
    function dequeue() {
   
        if (activeCount >= concurrency || queue.length === 0) return;

        activeCount++;

        // 从队列中取出一个请求参数
        const arg = queue.shift();

        // 执行请求,并将结果添加到结果数组中
        fn(arg).then(result => {
   
            results.push(result);
            activeCount--;
            dequeue(); // 递归调用以处理下一个请求
        }).catch(error => {
   
            console.error(`Error processing ${
     arg}:`, error);
            activeCount--;
            dequeue(); // 即使出错也继续处理下一个请求
        });
    }

    // 开始处理队列
    queue.forEach(() => dequeue());

    // 返回一个Promise,该Promise在所有请求完成后解决
    return new Promise(resolve => {
   
        if (queue.length === 0) {
   
            resolve(results);
        } else {
   
            // 当没有更多活动请求时,解析结果
            const interval = setInterval(() => {
   
                if (activeCount === 0 && queue.length === 0) {
   
                    clearInterval(interval);
                    resolve(results);
                }
            }, 100);
        }
    });
}

// 示例:使用fetch API模拟并发请求
function fetchData(url) {
   
    return fetch(url).then(response => response.json());
}

// 假设我们有一系列URL需要并发请求
const urls = [
    'https://api.example.com/data1',
    'https://api.example.com/data2',
    // ...更多URL
    'https://api.example.com/dataN'
];

// 并发限制为5
concurrentRequests(fetchData, urls, 5).then(results => {
   
    console.log('All data fetched:', results);
}).catch(error => {
   
    console.error('Failed to fetch all data:', error);
});

解释

  1. 并发控制:通过activeCount变量跟踪当前活动的请求数量,确保不超过设定的并发限制。
  2. 队列处理:使用queue数组来存储待处理的请求参数,并通过dequeue函数逐个处理它们。
  3. 递归调用:在请求成功或失败后,通过递归调用dequeue来处理下一个请求,以保持并发性。
  4. 结果收集:所有请求的结果都被收集到results数组中。
  5. 完成检测:使用setInterval来定期检查是否所有请求都已处理完毕,并在完成时解析返回的Promise。

结论

通过这种方法,我们可以有效地控制JavaScript中的并发任务数量,特别是在处理大量异步操作时非常有用。这种方法不仅适用于网络请求,还可以扩展到任何需要并发控制但受限于单线程环境的场景。

目录
相关文章
|
4月前
|
前端开发 JavaScript UED
理解宏任务和微任务:JavaScript 异步编程的必备知识(下)
理解宏任务和微任务:JavaScript 异步编程的必备知识(下)
理解宏任务和微任务:JavaScript 异步编程的必备知识(下)
|
4月前
|
前端开发 JavaScript 数据处理
理解宏任务和微任务:JavaScript 异步编程的必备知识(上)
理解宏任务和微任务:JavaScript 异步编程的必备知识(上)
理解宏任务和微任务:JavaScript 异步编程的必备知识(上)
|
13天前
|
前端开发 JavaScript API
JavaScript 的宏任务和微任务有什么区别
【9月更文挑战第6天】JavaScript 的宏任务和微任务有什么区别
15 4
|
23天前
|
运维 JavaScript 安全
自动化运维:使用Ansible简化日常任务深入理解Node.js事件循环和异步编程
【8月更文挑战第27天】在快节奏的技术环境中,自动化不再是奢侈品,而是必需品。本文将引导你通过Ansible实现自动化运维,从基础到高级应用,解锁高效管理服务器群的秘诀,让你的IT操作更加流畅和高效。
|
2月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的校园悬赏任务平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的校园悬赏任务平台附带文章源码部署视频讲解等
27 0
|
2月前
|
JavaScript 前端开发 API
js 运行机制(含异步机制、同步任务、异步任务、宏任务、微任务、Event Loop)
js 运行机制(含异步机制、同步任务、异步任务、宏任务、微任务、Event Loop)
29 0
|
3月前
|
JavaScript 前端开发
js中的宏任务与微任务
js中的宏任务与微任务
|
4月前
|
JavaScript 前端开发 测试技术
编写JavaScript模块化代码主要涉及将代码分割成不同的文件或模块,每个模块负责处理特定的功能或任务
【5月更文挑战第10天】编写JavaScript模块化代码最佳实践:使用ES6模块或CommonJS(Node.js),组织逻辑相关模块,避免全局变量,封装细节。利用命名空间和目录结构,借助Webpack处理浏览器环境的模块。编写文档和注释,编写单元测试以确保代码质量。通过这些方法提升代码的可读性和可维护性。
37 3
|
4月前
|
JavaScript 前端开发
前端 JS 经典:宏任务、微任务、事件循环(EventLoop)
前端 JS 经典:宏任务、微任务、事件循环(EventLoop)
41 0
|
4月前
|
存储 JavaScript 前端开发
JS的执行原理,一文了解Event Loop事件循环、微任务、宏任务
了解JavaScript的事件循环和任务队列对于处理异步任务至关重要。事件循环由主线程和任务队列组成,当主线程执行完同步任务后,会检查任务队列,按顺序执行宏任务和微任务。宏任务包括`setTimeout`等,微任务如`Promise`的回调。在实际开发中,事件循环保证了代码的非阻塞执行,提高了用户体验。例如,`setTimeout`的回调会在当前宏任务结束后,所有微任务执行完才会执行。理解这一机制对于解决面试中的异步问题非常有帮助。
55 0
JS的执行原理,一文了解Event Loop事件循环、微任务、宏任务