js限制Promise“并发”的数量——React项目实践
前言:
1、浏览器对同一域名下同一时间点的最大连接数做了限制,谷歌是6个,其他浏览器可百度查看相关资料。
2、浏览器同一时间点内发送的请求过多,会导致请求很慢页面卡顿的情况
解决问题
1、封装限制Promise异步任务并发请求数
核心函数也就两个。
调用器:就是把真正的执行函数和参数传入,创建返回一个新的Promise,而这个新Promise的什么时候返回,取决于这个异步任务何时被调度。Promise内部主要就是创建一个任务,判断任务是执行还是入队。
创建任务:实际上就是返回了一个函数,将真正的执行函数放在里面执行。这里利用了Promise的finally方法,在finally中判断是否执行下一个任务,实现任务队列连续消费的地方就是这里。
limitPromise.js
/*** 封装axios并发请求数*/
class LimitPromise {constructor (max) {// 异步任务“并发”上限this._max = max || 6;// 当前正在执行的任务数量this._count = 0;// 等待执行的任务队列this._taskQueue = [];}/*** 调用器,将异步任务函数和它的参数传入* @param caller 异步任务函数,它必须是async函数或者返回Promise的函数* @param args 异步任务函数的参数列表* @returns {Promise<unknown>} 返回一个新的Promise*/call (caller, ...args) {return new Promise((resolve, reject) => {const task = this._createTask(caller, args, resolve, reject);if (this._count >= this._max) {// console.log('count >= max, push a task to queue', this._count , this._max, this._taskQueue)this._taskQueue.push(task);} else {// console.log('数组中的对列长度还没超过6个', this._count)task();}})}/*** 创建一个任务* @param caller 实际执行的函数* @param args 执行函数的参数* @param resolve* @param reject* @returns {Function} 返回一个任务函数* @private*/_createTask (caller, args, resolve, reject) {return () => {// 实际上是在这里调用了异步任务,并将异步任务的返回(resolve和reject)抛给了上层caller(...args).then(resolve).catch(reject).finally(() => {// 任务队列的消费区,利用Promise的finally方法,在异步任务结束后,取出下一个任务执行this._count--;if (this._taskQueue.length) {// console.log('a task run over, pop a task to run', this._taskQueue)let task = this._taskQueue.shift();task();} else {// console.log('task count = ', count)}})this._count++;// console.log('task run , task count = ', this._count)}}}export default LimitPromise;
2、在我们封装的axios文件使用并发数限制
limitRequest.js
import axios from 'axios';
import { message } from 'antd';
import qs from 'qs';// 引入上面封装好的并发数限制文件
import LimitPromise from './limitPromise';// 并发请求上限
const MAX = 5;
// 调用核心控制器类
const limitP = new LimitPromise(MAX);//响应时间
axios.defaults.timeout = 300000; // 5 min
axios.defaults.headers.post['Content-Type'] = 'application/json';// request interceptor
axios.interceptors.request.use(config => {config.headers['Content-Type'] = 'application/json';config.headers['datae-token'] = localStorage.getItem('xyToken');//application/x-www-form-urlencodedif (config.resType === 'form') {config.headers['Content-Type'] ='application/x-www-form-urlencoded';config.data = qs.stringify(config.data);return config;}return config;},error => {return Promise.reject(error);}
);// response interceptor
axios.interceptors.response.use(response => {if (response.status >= 400) {// 没登录/过期if (response.status === 401) {message.error('登录态过期,请重新登录');// ...写入自己的代码逻辑和判断return;}return Promise.reject(response);}return response;},error => {if (error.response.status === 401) {message.error('登录态过期,请重新登录');// ...写入自己的代码逻辑和判断} else {message.error('网络连接超时');}return Promise.reject(error);}
);// 导出axios的几种请求方式
export const getP = (url, params, config = {}) => {return limitP.call(axios.get,url,{params: params,...config,}).then(res => res.data);
};export const postP = (url, params, config = {}) => {return limitP.call(axios.post,url,params,{...config,}).then(res => res.data);
};
// 如果还需要其他请求,请结合aixos的api进行相关配置export default axios;
3、统一封装的api的请求路径
api.js
import { getP, postP } from './tools/axios/limitRequest';
import {sysPrefix,
} from './configs';export default {// 首页(中控台)这也页面下的所有接口都是加载页面就进行请求的,可见这里的请求数很多home: {// 监控预警————等级xxxxxxxxxx: () => getP(`${sysPrefix}/warningInfo/xxxxx`),// 监控预警————xxxxxxxxxx: (params) => getP(`${sysPrefix}/warningInfo/xxxx`, params),// 监控预警————确认xxxx: (params) => postP(`${sysPrefix}/warningInfo/xxxx`, params),// 监控预警————清除xxx: (params) => postP(`${sysPrefix}/warningInfo/xxxx`, params),// 作业异常单————xxxxxxTab数据xxxxxx: (params) => getP(`${sysPrefix}/planResult/xxxx`, params),// 作业异常单————获取表格数据xxxx: (params) => postP(`${sysPrefix}/planResult/xxxxx`, params),// 作业异常单————表格中的处理按钮xxx: (params) => postP(`${sysPrefix}/planResult/xxxx`, params),// 我的导航————查询回显导航xxxxx: params => postP(`${sysPrefix}/system/navigation/xxxx`, params),// 我的导航————添加快捷入口导航xxxxxx: params => postP(`${sysPrefix}/system/navigation/xxxxx`, params),// 我的导航————更新最近访问导航xxxxxx: params => postP(`${sysPrefix}/system/navigation/xxxxx`, params),// Hadoop磁盘修复————请求表格数据xxxxx: (params) => postP(`${cdhnm}/diskFailureRecovery/xxxxx`, params),// Hadoop磁盘修复————xxxxxxxxxxx: (params) => postP(`${sysPrefix}/diskFailureRecovery/xxxx`, params),// Hadoop磁盘修复————xxxxxxxxxxxx: (params) => postP(`${sysPrefix}/diskFailureRecovery/xxxxx`, params),},
};
4、在组件页面中调用上面封装好的api
home.js
import api from 'src/api';// 下面只是简约写出请求部分的代码
useEffect(() => {api.home.xxxx().then(res => {console.log(res);}).catch((err) => {console.log(err);});// ......还有很多ajax请求}, []);
这样像在home.js中页面dom加载完成后一次性请求很多个接口的时候就会根据上面做的并发数限制进行有效的控制了。
推荐一篇好文:
JavaScript 中如何实现并发控制?
参考资料:https://www.jianshu.com/p/cc706239c7ef
js限制Promise“并发”的数量——React项目实践相关推荐
- React项目实践系列一
数据分析平台-实践系列一 项目创建于2018年1月底,到现在已经接近半年,在此写下半年来项目的实践过程以及自己对前端的学习与体悟. 技术选型 框架: React 路由: React-Router 4 ...
- 使用webpack5自己搭建react项目脚手架(手把手教,把手伸过来,好软~呸,好手)
问:目前前端最火的两大框架react和vue官方都有自己的成熟的cli脚手架,为什么还要自己搭建脚手架了? 答: 一.自己搭建脚手架可以根据自己公司的项目特征来决定使用哪些具体的插件或者编译方式,官方 ...
- 二手前端入门React项目
个人对ReactJS这门技术比较感兴趣,在基友的帮助下成功创建了一个React标准前端工程,过程中遇到了不少麻烦,今天作为笔记一般记录一下遇到的问题和解决方案. 基础环境 手头一台Mac 使用OSX系 ...
- react项目服务器Tomcat,tomcat部署react项目的方法
tomcat部署react项目的方法 发布时间:2020-12-16 09:44:42 来源:亿速云 阅读:151 作者:小新 这篇文章主要介绍了tomcat部署react项目的方法,具有一定借鉴价值 ...
- 中使用js修改变量值_谈一谈css-in-js在React项目中的使用
一.什么是css-in-js 参考:[css in js 简介] 简单来说,传统的前端方案推崇"关注点分离"原则,HTML.CSS.JavaScript 应该各司其职,进行分离. ...
- [react] 使用webpack打包React项目,怎么减小生成的js大小?
[react] 使用webpack打包React项目,怎么减小生成的js大小? 打包优化的问题解决思路: 代码压缩:UglifyjsWebpackPlugin 代码分组 commonsChunkPlu ...
- 了解CSS in JS(JSS)以及在React项目中配置并使用JSS
目录 认识JSS 什么是JSS JSS 的常见实现 JSS 的好处与坏处 好处 坏处 使用模块化CSS实现JSS 安装插件 在React项目中的tsconfig.json中添加配置 vscode项目中 ...
- react项目中使用three.js(解决纹理贴图路径问题)
一,本文解决如下问题 1. 在react脚手架的项目中使用three.js 2. three.js在react中使用动态的纹理贴图遇到的路径问题 3. this.指向的丢失问题 二,在项目中使用thr ...
- 前端—react项目及版本更新对比
介绍: 项目搭建逻辑:1)项目中index.html中渲染的内容.2)看main.js中绑定的组件渲染 React框架 由Facebock开源的一款前端框架. 工作中使用的版本: react:16.2 ...
最新文章
- C# 如何在ComboBox输入文字改变时,触发事件?
- RAID0,RAID1,RAID10,RAID5
- 问题 | 0x00007FF95287908C 处(位于 OpenCV.exe 中)有未经处理的异常: Microsoft C++ 异常: cv::Exception
- redis根据通配符去批量删除指令
- ES6公用跑马灯抽奖组件的封装及使用
- Flink中MapFunction以及其他各种xxxFunction在intellij中的用法和规律
- multinorm r语言_与心理学数据分析相关的R工具包
- Win32ASM学习[17]:条件跳转
- 八伟大的工具,Windows用户永远都不想错过
- 概述嵌入式设备驱动,教你怎么“玩”转嵌入式开发
- python生成器的使用_应该如何以及为什么使用Python生成器
- 可变字典 NSMutableDictionary
- 【Elasticsearch】Elasticsearch 7.3 的 offheap 原理
- 【Redis】redis 配置 配置文件 redis.conf
- 获取当前程序的相当路径
- mac 自带连接ftp服务器,Mac自带FTP工具使用
- python 网络音乐播放器(二):tkinter 实现歌词同步滚动
- 计算机网络发现已关闭啥意思,电脑显示网络发现已关闭,是什么意思?怎样解决问题?...
- Python爬虫抓取链家二手房数据
- 二进制枚举子集(总结+应用)
热门文章
- PermissionError: [Errno 13] Permission denied: ‘D:\\******‘
- 2679 Adventurous Driving 解题报告
- 树莓派3B+ 串口使用大全(实现串口通信功能)
- html5 图片横向滑动效果,JS实现图片横向滚动效果示例代码
- 高度决定视野眼界决定世界
- 2019年10月18日作业题解
- 线性回归及logistic回归详解
- 曝阿里达摩院大模型 M6 带头人杨红霞已离职:个人选择,非行业原因
- QM-4 服务质量与QFD
- VS中toolstrip控件去除下灰线边框