JavaScript前端控制网络并发数目的常见方法小结

 更新时间:2023年12月22日 10:40:20   作者:慕仲卿  
控制前端发起请求的并发数,即限制同一时间内进行处理的请求数量,是一种有效的策略,本文将详细介绍前端控制并发数的几种常见做法,希望对大家有所帮助

在现代Web应用开发中,提高用户体验的同时要确保服务器负载平衡是至关重要的。控制前端发起请求的并发数,即限制同一时间内进行处理的请求数量,是一种有效的策略。本文将详细介绍前端控制并发数的几种常见做法,并且提供具体的代码示例。

队列机制

队列是实现并发控制常用的数据结构。它遵循先进先出(FIFO)的原则,能够按照请求到达的顺序逐一处理。

示例:基于 Promise 的请求队列

在JavaScript中,可以利用Promise来实现一个简单的请求队列。下面是一个示例代码:

class PromiseQueue {
  constructor(maxConcurrent) {
    this.maxConcurrent = maxConcurrent;
    this.queue = [];
    this.currentCount = 0;
  }

  add(promiseCreator) {
    return new Promise((resolve, reject) => {
      this.queue.push({
        promiseCreator,
        resolve,
        reject
      });
      this.tryToRun();
    });
  }

  tryToRun() {
    if (this.queue.length === 0 || this.currentCount >= this.maxConcurrent) {
      return;
    }
    this.currentCount++;
    const { promiseCreator, resolve, reject } = this.queue.shift();
    promiseCreator().then(resolve, reject).finally(() => {
      this.currentCount--;
      this.tryToRun();
    });
  }
}

利用此队列可以如下方式控制并发:

// 实例化队列,设置最大并发数为 2
const queue = new PromiseQueue(2);

// 添加请求到队列
queue.add(() => fetch(url1)).then(handleResponse);
queue.add(() => fetch(url2)).then(handleResponse);
queue.add(() => fetch(url3)).then(handleResponse);

在此示例中,只有两个请求会立即执行,第三个请求会等待前两个中的某个完成后再开始。

控制并发的库

市面上有许多专门用于控制并发的JavaScript库,如p-limit, async等。

示例:使用 p-limit 控制并发

p-limit是一个轻量级的库,可以方便地限制并发数:

import pLimit from 'p-limit';

const limit = pLimit(2);

const input = [
    limit(() => fetch(url1)),
    limit(() => fetch(url2)),
    limit(() => fetch(url3)),
    limit(() => fetch(url4)),
];

// 只有 2 个请求被同时处理
Promise.all(input).then(results => {
    // 处理结果
});

在上述代码中,limit函数会保证同时只有两个请求在处理。

XMLHttpRequest的abort方法

在使用XMLHttpRequest(XHR)对象发送请求时,可以在请求数量超过设定的并发限制时调用abort方法来取消请求。

示例:使用XMLHttpRequest和abort控制并发

const MAX_CONCURRENT = 2;
let concurrentCount = 0;
const xhrPool = [];

function fetchWithXhr(url) {
    if (concurrentCount >= MAX_CONCURRENT) {
        setTimeout(() => fetchWithXhr(url), 200); // 200ms 后重试
        return;
    }
    concurrentCount++;
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => {
        handleResponse(xhr.response);
        concurrentCount--;
        if (xhrPool.length > 0) {
            const newXhr = xhrPool.shift();
            fetchWithXhr(newXhr.url);
        }
    };
    xhr.onerror = xhr.onabort = () => {
        concurrentCount--;
    };
    xhr.send();
}

function abortExtraRequests() {
    while (concurrentCount > MAX_CONCURRENT) {
        const xhrToAbort = xhrPool.pop();
        xhrToAbort.abort();
    }
}

// 发起请求
fetchWithXhr("https://api.example.com/data1");
fetchWithXhr("https://api.example.com/data2");
fetchWithXhr("https://api.example.com/data3");

在此示例中,超出并发限制的请求将会被推迟执行,而非立即取消;并且可以使用abortExtraRequests函数对并发数目进行校验,去除超过的部分。

Fetch API的AbortController

Fetch API提供了AbortController接口,通过它可以随时取消一个或多个请求。

示例:使用AbortController控制并发

const MAX_CONCURRENT = 2;
let concurrentCount = 0;
const controllerQueue = new Map();

async function fetchWithAbortController(url) {
    if (concurrentCount >= MAX_CONCURRENT) {
        await new Promise(resolve => setTimeout(resolve, 200)); // 200ms 后重试
        return fetchWithAbortController(url);
    }

    const controller = new AbortController();
    concurrentCount++;
    controllerQueue.set(url, controller);

    try {
        const response = await fetch(url, { signal: controller.signal });
        handleResponse(await response.json());
    } catch (error) {
        // 错误处理
    } finally {
        controllerQueue.delete(url);
        concurrentCount--;
        if (__yourCondition) {
            controllerQueue.get(__specificUrl).abort(); // 取消下一个请求
        }
    }
}

// 发起请求
fetchWithAbortController("https://api.example.com/data1");
fetchWithAbortController("https://api.example.com/data2");
fetchWithAbortController("https://api.example.com/data3");

在这个例子中,AbortController用于取消等待队列中的请求,而且每个请求都有自己的AbortController实例。

通过以上方法,可以有效控制前端并发数,避免服务器过载且优化用户体验。不需修改服务器配置或缩放服务器资源即可实现前端请求的优雅管理。这些策略对于构建响应速度快、资源使用高效的Web应用至关重要。

以上就是JavaScript前端控制网络并发数目的常见方法小结的详细内容,更多关于JavaScript控制网络并发的资料请关注脚本之家其它相关文章!

相关文章

  • Vue为div标签设置assets内本地背景图片的实现方法

    Vue为div标签设置assets内本地背景图片的实现方法

    在 Vue 中为 <div> 设置 assets 目录下的本地背景图片,需要通过 Webpack 或 Vite 等构建工具 处理路径引用,本文通过代码示例给大家介绍了详细实现方法,需要的朋友可以参考下
    2025-05-05
  • JavaScript对象合并实现步骤介绍

    JavaScript对象合并实现步骤介绍

    这篇文章主要介绍了JavaScript对象合并实现步骤,为什么要合并?这是我在重构代码的时候的一个需求。简单来说,我会有若干个对象需要合并为一个对象。而这些对象为两层,如果直接展开或者赋值会涉及到深拷贝
    2023-01-01
  • JS删除某个父元素下的所有子元素

    JS删除某个父元素下的所有子元素

    JS中如何删除某个父元素下的所有子元素?这里我介绍几种方法,结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • JavaScript/jQuery实现切换页面效果

    JavaScript/jQuery实现切换页面效果

    这篇文章主要为大家详细介绍了JavaScript或jQuery实现切换页面效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • 深入了解JavaScript中的函数式编程

    深入了解JavaScript中的函数式编程

    JavaScript是一门多范式的编程语言,其中函数式编程成为了一种受欢迎的范式之一,本文将带您深入了解JavaScript函数式编程的核心概念和技术,需要的可以参考一下
    2023-06-06
  • 亲自教你TypeScript 项目搭建过程

    亲自教你TypeScript 项目搭建过程

    这篇文章主要介绍了亲自教你TypeScript 项目搭建过程,我记得前一天,我们配置过一份 webpack 配置,直接复制过来使用,这里就不多说了,然后就是在项目中引入我们的 less,需要的朋友可以参考下
    2022-11-11
  • JavaScript获取和操作时间戳的用法详解

    JavaScript获取和操作时间戳的用法详解

    这篇文章主要介绍了JavaScript获取和操作时间戳的相关资料,时间戳通常用于记录时间、计算时间差、生成唯一的标识符等,文章详细讲解了如何使用Date.now()和new Date().getTime()获取当前时间戳,需要的朋友可以参考下
    2025-04-04
  • layui 数据表格+分页+搜索+checkbox+缓存选中项数据的方法

    layui 数据表格+分页+搜索+checkbox+缓存选中项数据的方法

    今天小编就为大家分享一篇layui 数据表格+分页+搜索+checkbox+缓存选中项数据的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-09-09
  • javascript跟随滚动效果插件代码(javascript Follow Plugin)

    javascript跟随滚动效果插件代码(javascript Follow Plugin)

    这篇文章介绍了javascript跟随滚动效果插件代码(javascript Follow Plugin),有需要的朋友可以参考一下
    2013-08-08
  • 开发中常用的25个JavaScript单行代码(小结)

    开发中常用的25个JavaScript单行代码(小结)

    这篇文章主要介绍了开发中常用的25个JavaScript单行代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-06-06

最新评论