当前位置: 首页 > article >正文

【前端并发请求控制:必要性与实现策略】

前端并发请求控制:必要性与实现策略

一、引言

在现代 Web 开发中,处理大量异步请求是一个常见场景。虽然浏览器和服务器都有其并发限制机制,但前端实现并发控制仍然具有其独特的价值和必要性。本文将深入探讨这个话题。

二、现有的并发限制机制

2.1 浏览器限制

浏览器对并发请求有默认的限制:

// 主流浏览器的并发限制(同一域名)
const browserLimits = {Chrome: 6,Firefox: '6-8',Safari: 6,Edge: 6
};// 但这个限制是按域名的
const requests = ['https://api1.example.com/data',  // 域名1:可以6个并发'https://api2.example.com/data',  // 域名2:可以6个并发'https://api3.example.com/data'   // 域名3:可以6个并发
];

2.2 服务器限制

服务器通常通过限流来控制并发:

// 典型的服务器限流响应
{status: 429,message: 'Too Many Requests',retry_after: 30
}

三、为什么需要前端并发控制

3.1 资源优化

// 不控制并发的问题
urls.forEach(async url => {try {await fetch(url);} catch (e) {if (e.status === 429) {// 1. 请求已经发出,消耗了资源// 2. 服务器已经处理了请求// 3. 网络带宽已经使用retry(url);}}
});// 控制并发的优势
await fetchWithLimit(urls, 5);
// 1. 预防性控制,避免资源浪费
// 2. 减少服务器压力
// 3. 优化网络资源使用

3.2 更好的用户体验

// 带进度反馈的并发控制
async function fetchWithProgress(urls, limit = 5) {let completed = 0;const total = urls.length;return fetchWithLimit(urls, limit, {onProgress: () => {completed++;updateUI(`进度:${completed}/${total}`);},onError: (error, url) => {showError(`请求失败:${url}`);}});
}

四、实现并发控制

4.1 基础实现

async function fetchWithLimit(urls, limit = 5) {const results = [];const executing = new Set();for (const url of urls) {const promise = fetch(url).then(response => {executing.delete(promise);return response;});executing.add(promise);results.push(promise);if (executing.size >= limit) {await Promise.race(executing);}}return Promise.all(results);
}

4.2 增强版实现

class RequestController {constructor(options = {}) {this.limit = options.limit || 5;this.timeout = options.timeout || 5000;this.retries = options.retries || 3;this.queue = [];this.executing = new Set();}async addRequest(url, options = {}) {const request = {url,priority: options.priority || 0,retryCount: 0};this.queue.push(request);this.processQueue();}async processQueue() {if (this.executing.size >= this.limit) {return;}// 按优先级排序this.queue.sort((a, b) => b.priority - a.priority);while (this.queue.length && this.executing.size < this.limit) {const request = this.queue.shift();this.executeRequest(request);}}async executeRequest(request) {const promise = this.fetchWithTimeout(request).catch(error => this.handleError(request, error));this.executing.add(promise);promise.finally(() => {this.executing.delete(promise);this.processQueue();});return promise;}async fetchWithTimeout(request) {const controller = new AbortController();const timeoutId = setTimeout(() => controller.abort(), this.timeout);try {const response = await fetch(request.url, {signal: controller.signal});clearTimeout(timeoutId);return response;} catch (error) {clearTimeout(timeoutId);throw error;}}async handleError(request, error) {if (request.retryCount < this.retries) {request.retryCount++;this.queue.unshift(request);await new Promise(resolve => setTimeout(resolve, Math.pow(2, request.retryCount) * 1000));} else {throw error;}}
}

五、实际应用场景

5.1 文件上传

class FileUploader {constructor(options = {}) {this.controller = new RequestController(options);this.chunkSize = options.chunkSize || 1024 * 1024;}async uploadFile(file) {const chunks = this.splitFile(file);const uploads = chunks.map((chunk, index) => ({url: '/upload',body: chunk,priority: chunks.length - index // 优先上传文件的前面部分}));return this.controller.addRequests(uploads);}
}

5.2 数据批量处理

class DataProcessor {constructor(options = {}) {this.controller = new RequestController(options);}async processDataset(items) {const batches = this.createBatches(items, 100);return this.controller.addRequests(batches.map(batch => ({url: '/process',body: batch,priority: batch.some(item => item.isUrgent) ? 1 : 0})));}
}

六、最佳实践建议

动态调整并发数:

function getOptimalConcurrency() {const connection = navigator.connection;if (!connection) return 5;switch (connection.effectiveType) {case '4g': return 6;case '3g': return 4;case '2g': return 2;default: return 3;}
}

实现优先级控制:

const priorities = {HIGH: 3,MEDIUM: 2,LOW: 1
};requests.sort((a, b) => b.priority - a.priority);

错误处理和重试策略:

async function retryWithBackoff(fn, maxRetries = 3) {for (let i = 0; i < maxRetries; i++) {try {return await fn();} catch (error) {if (i === maxRetries - 1) throw error;await delay(Math.pow(2, i) * 1000);}}
}

七、总结

前端并发控制虽然看似多余,但实际上是提升应用性能和用户体验的重要手段:

优势:

  • 预防性能问题
  • 提供更好的用户体验
  • 更灵活的控制策略
  • 更优雅的错误处理

实现考虑:

  • 动态并发数调整
  • 请求优先级
  • 超时处理
  • 错误重试
  • 进度反馈

应用场景:

  • 文件上传下载
  • 数据批量处理
  • API 批量调用
  • 资源预加载

通过合理的并发控制,我们可以在保证应用性能的同时,提供更好的用户体验。这不仅仅是一个技术问题,更是一个用户体验和资源优化的问题。

相关文章:

【前端并发请求控制:必要性与实现策略】

前端并发请求控制&#xff1a;必要性与实现策略 一、引言 在现代 Web 开发中&#xff0c;处理大量异步请求是一个常见场景。虽然浏览器和服务器都有其并发限制机制&#xff0c;但前端实现并发控制仍然具有其独特的价值和必要性。本文将深入探讨这个话题。 二、现有的并发限制…...

LeetCode 139. 单词拆分(Word Break) - 动态规划深度解析

文章目录 问题描述动态规划解法解法核心思路完整代码实现关键代码解析1. 数据结构初始化2. 动态规划数组3. 核心循环逻辑4. 子串区间理解(关键)示例演算复杂度分析算法优化点总结本文详细解析LeetCode 139题"单词拆分"的动态规划解法,涵盖核心思路、代码实现、区间…...

@Prometheus动态配置管理-ConsulConfd

文章目录 动态配置管理 Consul Confd**一、目标****二、架构组件****三、环境准备****四、配置 Consul**1. 注册监控目标&#xff08;服务发现&#xff09;2. 存储告警规则&#xff08;KV 存储&#xff09; **五、配置 Confd**1. 监控目标模板配置2. 告警规则模板配置 **六、配…...

CentOS7 + JDK8 虚拟机安装与 Hadoop + Spark 集群搭建实践

前言 在大数据时代&#xff0c;Hadoop 和 Spark 是两种非常重要的分布式计算框架。本文将详细介绍如何在 CentOS7 JDK8 的虚拟机环境中搭建 Hadoop Spark 分布式集群&#xff0c;包括 Spark Standalone 和 Hadoop Spark on YARN 两种模式&#xff0c;并提供具体的代码示例。…...

从OSI到TCP/IP:网络协议的演变与作用

个人主页&#xff1a;chian-ocean 文章专栏-NET 从OSI到TCP/IP&#xff1a;网络协议的演变与作用 个人主页&#xff1a;chian-ocean文章专栏-NET 前言网络发展LANWAN 协议举个例子&#xff1a; 协议的产生背景 协议的标准化OSI模型参考OSI各个分层的作用各层次的功能简介 TCP/…...

Stream流性能分析及优雅使用

文章目录 摘要一、Stream原理解析1.1、Stream总概1.2、Stream运行机制1.2.1、创建结点1.2.1、搭建流水线1.2.3、启动流水线 1.3、ParallelStream 二、性能对比三、优雅使用3.1 Collectors.toMap()3.2 findFirst()&#xff0c;findAny()3.3 增删元素3.4 ParallelStream 四、总结…...

iOS 电子书听书功能的实现

在 iOS 应用中实现电子书听书&#xff08;文本转语音&#xff09;功能&#xff0c;可以通过系统提供的 AVFoundation 框架实现。以下是详细实现步骤和代码示例&#xff1a; 核心步骤&#xff1a; 导入框架创建语音合成器配置语音参数实现播放控制处理后台播放添加进度跟踪 完整…...

【和春笋一起学C++】(十七)C++函数新特性——内联函数和引用变量

C提供了新的函数特性&#xff0c;使之有别于C语言。主要包括&#xff1a; 内联函数&#xff1b;按引用传递变量&#xff1b;默认参数值&#xff1b;函数重载&#xff08;多态&#xff09;&#xff1b;模版函数&#xff1b; 因篇幅限制&#xff0c;本文首先介绍内联函数和引用…...

GitHub 趋势日报 (2025年06月02日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 1339 prompt-eng-interactive-tutorial 1080 courses 624 onlook 596 system-desi…...

卫星的“太空陀螺”:反作用轮如何精准控制姿态?

卫星的“太空陀螺”&#xff1a;反作用轮如何精准控制姿态&#xff1f; 在距地面500公里的轨道上&#xff0c;一颗遥感卫星正以7.8km/s的速度飞越目标区域。此时星载计算机发出指令&#xff1a;“滚转15并对准目标点”。短短数秒后&#xff0c;数吨重的卫星如同被无形之手推动般…...

proteus新建工程

1 点击新建工程 2 输入项目名&#xff0c;选择工程文件夹 3 下一步 4 不创建pcb 5 直接下一步 6 点击完成 7 创建完毕...

缓存击穿 缓存穿透 缓存雪崩

缓存击穿 缓存穿透 缓存雪崩 在日常开发中&#xff0c;我们经常会在后端引入 Redis 缓存来减轻数据库压力、提高访问性能。本文将逐点介绍 Redis 缓存常见问题及解决策略。 缓存穿透 问题描述&#xff1a; 缓存穿透指的是客户端请求的数据&#xff0c;在缓存中和数据库中都不…...

RTC实时时钟DS1338Z-33/PT7C433833WEX国产替代FRTC1338S

FRTC1338S是NYFEA徕飞公司推出的一种高性能的实时时钟芯片&#xff0c;它采用了SOP8封装技术&#xff0c;这种技术因其紧凑的尺寸和出色的性能而被广泛应用于各类电子设备中。 FRTC1338S串行实时时钟(RTC)是一种低功耗的全二进制编码十进制(BCD)时钟/日历外加56字节的非易失性…...

Redis命令使用

Redis是以键值对进行数据存储的&#xff0c;添加数据和查找数据最常用的2个指令就是set和get。 set&#xff1a;set指令用来添加数据。把key和value存储进去。get&#xff1a;get指令用来查找相应的键所对应的值。根据key来取value。 首先&#xff0c;我们先进入到redis客户端…...

【免费数据】1980-2022年中国2384个站点的水质数据

水&#xff0c;是生命之源&#xff0c;关乎着地球上每一个生物的生存与发展。健康的水生生态系统维持着整个水生态的平衡与活力&#xff1b;更是确保人类能持续获得清洁水源的重要保障。水质数据在水质研究、海洋生物量测算以及生物多样性评估等诸多关键领域都扮演着举足轻重的…...

Java基础 Day28 完结篇

一、方法引用 对 Lambda 表达式的进一步简化 方法引用使用一对冒号 :: Tips&#xff1a;静态方法用类名加双冒号&#xff0c;非静态方法用对象名加双冒号 通过方法的名字来指向一个方法 参数可推导即可省略 可以使语言的构造更紧凑简洁&#xff0c;减少冗余代码 二、单元…...

小红薯商品搜索详情分析与实现

前言 小红书作为国内知名的社交电商平台,拥有丰富的商品数据和用户评价信息。对于数据分析师、产品经理或电商从业者来说,能够获取小红书的商品数据具有重要的商业价值。本文将详细介绍如何通过逆向工程实现小红书商品搜索API的调用。 免责声明:本文仅用于技术学习和研究目…...

Git 极简使用指南

Git 是一个强大的分布式版本控制系统&#xff0c;但入门只需要掌握几个核心概念和命令。本指南旨在帮助你快速上手&#xff0c;处理日常开发中最常见的 80% 的场景。 核心概念 仓库 (Repository / Repo): 你的项目文件夹&#xff0c;包含了项目的所有文件和完整的历史记录。…...

力扣刷题Day 69:搜索二维矩阵(74)

1.题目描述 2.思路 首先判断target是否有可能在矩阵的某一行里&#xff0c;没可能直接返回False&#xff0c;有可能就在这一行里二分查找。 3.代码&#xff08;Python3&#xff09; class Solution:def searchMatrix(self, matrix: List[List[int]], target: int) -> boo…...

c#压缩与解压缩-SharpCompress

SharpCompress SharpCompress 是一个开源项目库&#xff0c;能够处理文件。c#库对于压缩已经有很多&#xff0c;可以随意选择&#xff0c;看了SharpCompress感觉比较简洁&#xff0c;还是介绍给大家。 项目地址&#xff1a; sharpcompress 项目使用 引入nuget包&#xff1…...

Neo4j 安全深度解析:原理、技术与最佳实践

在当今数据驱动的世界中&#xff0c;图数据库承载着关键的关系信息&#xff0c;其安全性至关重要。Neo4j 提供了一套多层次、纵深防御的安全体系。 Neo4j 的安全体系提供了从认证授权到数据加密、审计追溯的完整解决方案。安全不是单一功能而是一种持续状态&#xff0c;其有效…...

MySQL指令个人笔记

MySQL学习&#xff0c;SQL语言笔记 一、MySQL 1.1 启动、停止 启动 net start mysql83停止 net stop mysql831.2 连接、断开 连接 mysql -h localhost -P 3306 -u root -p断开 exit或者ctrlc 二、DDL 2.1 库管理 2.1.1 直接创建库 使用默认字符集和排序方式&#xf…...

2022年 国内税务年鉴PDF电子版Excel

2022年 国内税务年鉴PDF电子版Excelhttps://download.csdn.net/download/2401_84585615/89784658 https://download.csdn.net/download/2401_84585615/89784658 2022年国内税务年鉴是对中国税收政策、税制改革和税务管理实践的全面总结。这份年鉴详细记录了中国税收系统的整体状…...

基于Java的OPCDA采集中间件

1.软件功能及技术特点简介&#xff1a; 软件功能及技术特点简介&#xff1a; OPCDA是基于Java语言开发的OPC client&#xff08;OPC客户端&#xff09;跨平台中间件软件&#xff0c;他支持OPC SERVER的OPC DA1.0/2.0/3.0。OPCDA实时采集数据&#xff08;包括实时数据、报警数…...

基于PyQt5的相机手动标定工具:原理、实现与应用

基于PyQt5的相机手动标定工具:原理、实现与应用 一、背景介绍二、功能详解与实现原理2.1 图像加载与预处理2.2 交互式透视调整2.3 透视变换数学原理2.4 图像拼接核心技术2.5 用户界面优化细节三、完整使用流程四、应用场景实例五、技术优势分析六、代码七、总结一、背景介绍 …...

vue2 项目中 npm run dev 运行98% after emitting CopyPlugin 卡死

今天在运行项目时&#xff0c;发现如下问题&#xff1a; 开始以为是node_modules依赖的问题&#xff0c;于是重新 npm install&#xff0c;重启项目后还是未解决。 在网上找了一圈发现有人说是 require引入图片地址没有写。在我的项目中排查没有这个问题&#xff0c;最后发现某…...

JavaScript 性能优化实战:从原理到框架的全栈优化指南

在 Web 应用复杂度指数级增长的今天&#xff0c;JavaScript 性能优化已成为衡量前端工程质量的核心指标。本文将结合现代浏览器引擎特性与一线大厂实践经验&#xff0c;构建从基础原理到框架定制的完整优化体系&#xff0c;助你打造高性能 Web 应用。 一、性能优化基础&#x…...

2025年- H61-Lc169--74.搜索二维矩阵(二分查找)--Java版

1.题目描述 2.思路 方法一&#xff1a; 定义其实坐标&#xff0c;右上角的元素&#xff08;0&#xff0c;n-1&#xff09;。进入while循环&#xff08;注意边界条件&#xff0c;行数小于m&#xff0c;列数要&#xff1e;0&#xff09;从右上角开始开始向左遍历&#xff08;比当…...

微服务商城-用户微服务

数据表 用户表 CREATE DATABASE user; USE user;CREATE TABLE user (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 用户ID,username varchar(50) NOT NULL DEFAULT COMMENT 用户名,password varchar(50) NOT NULL DEFAULT COMMENT 用户密码&#xff0c;MD5加密…...

数学复习笔记 26

5.25&#xff1a;这题还是有点难度的。主要是出现了新的知识点&#xff0c;我现在还没有那么熟悉这个新的知识点。这块就是&#xff0c;假设一个矩阵可以写成一个列向量乘以一个行向量的形式&#xff0c;这两个向量都是非零向量&#xff0c;那么这个矩阵的秩等于一。这个的原理…...