Loading... > @author: 郭瑞峰 > > @createTime: 2023/09/26 > > @updateTime: 2023/09/26 ## 哔哔啵啵的前言 不得不吐槽了这两天开发,开发三方系统的概览页面,概览页面最大的特点就是图表多,还有并发请求。当然,我那个页面也就要请求48个接口,也不。。。多?? 卧槽,48个接口,后端呢?救我一下啊,后端还有200个bug(或者说是票)等着解决呢。 emmm,48个接口,玩我呢? emmm,肯定不能一次性并发请求,不然要炸 但是,万一能行呢? ## 不出意料的崩了 第一步,我们宣称48个没有什么事儿,直接套用现成的接口并发请求。  一切都好,48个接口一个都没报错 第二次测试时候,三方服务器炸了 ~~(有的时候要从服务器上面找原因好吧,这么多年都是这么卡,有没有认真工作,好不好)~~  没办法,只有老老实实地分流请求 ## 解决方案 用我不太聪明的小脑瓜想了想,想到仨解决方案 ### 修改 axios maxContentLength 属性 若是用 `axios` 库的话,可以修改`maxContentLength`属性值来限制并发请求,当超过上限时候就会进入等待(可能是等待队列,这个后续自己调研一下把) ```javascript import axios from 'axios' const request = axios.create({ maxContentLength: 10 }) export default request ``` 但最后否定了,原因在于`axios`已经进行过二次封装,不能随便更改(即使这个改动对其他模块无任何影响) ### 分流使用 Promise.all 注意:用的是`Promise.all`不是`Promise.any` `Promise.all`是等所有数组`resolve`后执行`then` `Promise.any`是数组有一个`resolve`后执行`then` 先上代码吧,可以用浏览器开发工具运行一下 ```javascript const promise = (index) => new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() <= 0.5) { resolve(`Promise ${index} run success`) } else { reject(`Promise ${index} get error`) } }, Math.random() * 1000) }) // 举个50并发的例子 const list = new Array(50).fill((index) => promise(index)) const running = (index) => { if (index >= list.length) return Promise.all([ list[index](index), list[index + 1](index + 1), list[index + 2](index + 2), list[index + 3](index + 3), list[index + 4](index + 4) ]) .then((valueList) => { console.log('Promise.all run successfully') console.log(valueList) console.log('\n') }) .catch(error => { console.log('Promise.all get error') console.log(error) console.log('\n') }) .finally(() => { running(index + 5) }) } running(0) ``` **优点:** 方便简单,通过分段方式解决了高并发请求 **缺点也很明显:** 1. 同一批请求内要是有一个请求异常,其他同批次的请求就不会有后续操作 2. 后续二次开发,迭代开发时候需要重新理一遍`Promise.all`的`then`返回值的顺序 ### 多个链式请求 链式请求的实质是等待上一个请求完成后执行下一个请求(这可能是我自创的定义,也许有其他名词形容,希望大佬们评论区教我做人) 还是老样子,先上代码 ```javascript const promise = (index) => new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() <= 0.5) { resolve(`Promise ${index} run success`) } else { reject(`Promise ${index} get error`) } }, Math.random() * 1000) }) .then(data => { console.log(data) return list }) .catch(error => { console.log(error) return list }) const list = new Array(50).fill(index => promise(index)) const promise = (index) => new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() <= 0.5) { resolve(`Promise ${index} run success`) } else { reject(`Promise ${index} get error`) } }, Math.random() * 1000) }) .then(data => { console.log(data) return list }) .catch(error => { console.log(error) return list }) const list = new Array(50).fill(index => promise(index)) const running = () => { let count = 0 const worker = () => { if (count >= list.length) return // 设置退出条件 list[count](count++) .then(() => { worker() }) } // 设置五个链 worker() worker() worker() worker() worker() } running() ``` 在每个`Promise`中的`then`和`catch`中`return`并发请求对象,这样当前接口执行完成后就可以继续执行`then`,然后再`then`中调用对应接口(这边建议使用对象方式调用,方便阅读和迭代开发) **优点:** 1. 每个请求以及后续处理相互独立,互不干扰 2. 通过设置多个链式来削减并发请求数量 **缺点很明显:** 1. 每个接口都要写后续操作以及异常处理,最后都要返回接口列表/对象 2. `then`执行会很杂乱 3. 会出现单链忙碌,其他链围观(接口简单,老早就摸鱼了) ## 最终 考虑再三,咱最终使用`链式请求`,很意外吧,居然不用`Promise.all`的方法 那么说一下为啥咱用`链式请求`,在于这是概览页面,每个接口后续处理必须相互独立。 若是有啥好的建议欢迎大佬们在评论区说一下  最后修改:2024 年 11 月 27 日 © 允许规范转载 赞 0 如果觉得我的文章对你有用,请随意赞赏