建立网站专业公司/网站外包
本文作者为360奇舞团前端工程师
前言
最近在做一个
AIGC
项目,后端基于Koa2
实现。其中有一个需求就是调用兄弟业务线服务端AIGC
能力生成图片。但由于目前兄弟业务线的AIGC
项目也是处于测试阶段,能够提供的服务器资源有限,当并发请求资源无法满足时,会响应【服务器繁忙】,这样对于C
端展示的我们是非常不友好的。基于当前的困境,第一想到的解决方案就是Kafka
或RabbitMQ
,但实际上对于我们目前的用户体量来说,简直就是大材小用。于是转换思路,是不是可以利用js模拟队列的方式解决问题呢,答案是:可以,Promise
的Resolve
队列!
分析
Resolve
的理解
Promise
的核心用法就是利用 Resolve
函数做链式传递。例如:
new Promise(resolve => {resolve('ok')
}).then(res => {console.log(res)
})
// 输出结果:ok
通过上边的例子我们可以理解,Resolve
将 Promise
对象的状态从 pending
变为 fullfilled
,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。
核心点:异步
此时抛出一个问题:假如我把 resolve
回调函数都放入一个队列里,Promise
是不是一直处于pending
状态?pending
状态就意味着then函数一直处于 waitting
状态,直到队列中的 resolve
函数执行后,then
函数才能被执行?
制造阻塞的 Promise
函数
const queue = []
new Promise(resolve => {queue.push(resolve)
}).then(res => {console.log(res)
})
// 输出结果:Promise {<pending>}queue[0]('ok')
// 输出结果:ok
为了佐证,直接贴图:

异步转同步
Koa2
属于洋葱模型,当请求过来以后需要调用 next
函数继续穿透,而我们的需求是限流,这意味着我们要阻塞请求,此时此刻,await
举起了双手,阻塞这种不要脸的事我在行呀!
const queue = []
const fn = async = () => {await new Promise(resolve => {queue.push(resolve)})// ...一大波操作
}
// queue[0]()
如果 queue[0]
不执行,代码就会一直处于阻塞状态。那我们就可以利用await写一个中间件实现阻塞某些 api
的需求了。
// 阻塞所有请求,知道queue中的resolve函数被执行才会执行next
const queue = []
module.exports = function () {return async function (ctx, next) {await new Promise(resolve => {queue.push(resolve)})await next();};
};
实现中间件
原理和思路都捋直了,那就开搞吧。话不多说,贴代码:
const resolveMap = {};/*** 请求队列* @param {*} ctx* @param {*} ifer 是否是图生图* @param {*} maxReqNumber 最大请求数量* @returns* @description* 使用promise解决请求队列问题* 1. 用于限制aicg的并发请求* 2. 当文生图是,根据风格分类存储resolve,当前请求响应完成时,触发消费队列中下一个请求* 3. 当图生图是,直接存储resolve到image风格,当前请求响应完成时,触发消费队列中下一个请求* 4. 同时处理的请求数量不超过maxReqNumber个,否则加入队列等待。*/
function requestQueue(ctx, maxReqNumber) {const params = ctx.request.body ?? ctx.request.query ?? ctx.request.params ?? {};const style = params.style ?? 'pruned_cgfull';resolveMap[style] = resolveMap[style] || { list: [], processNumber: 0 };const currentResolve = resolveMap[style];((currentResolve) => {ctx.res.on('close', () => {saveNumberMinus(currentResolve);// 当前请求响应完成时,触发消费队列中下一个请求if (currentResolve.list.length !== 0) {const node = currentResolve.list.shift();node.resolve();currentResolve.processNumber++;}currentResolve = null;});})(currentResolve);// 当前请求正在处理中,将resolve存储到队列中if (currentResolve.processNumber + 1 > maxReqNumber) {// 利用promise阻塞请求return new Promise((resolve, reject) => {// 当前请求正在处理中,将resolve存储到队列中currentResolve.list.push({ resolve, reject, timeStamp: Date.now(), params });});} else {currentResolve.processNumber++;return Promise.resolve();}
}module.exports = function (options = {}) {const { maxReqNumber = 2, apis = [] } = options;return async function (ctx, next) {const url = ctx.url;if (apis.includes(url)) {try {await requestQueue(ctx, maxReqNumber);} catch (error) {console.log(error);ctx.body = {code: 0,msg: error,};return;}}await next();};
};const fiveMinutes = 5 * 60 * 1000;
setInterval(() => {Object.values(resolveMap).forEach((item) => {const { timeStamp, resolve } = item;if (Date.now() - timeStamp > fiveMinutes) {resolve(); // 执行并释放请求,防止用户请求因异常积压导致一直挂起saveNumberMinus(item);}});
}, 5 * 60 * 1000);
这里要着重提示一点,闭包的使用。之所以使用闭包是为了保证当前请求的
close
事件触发时能够使用currentResolve
对象。因为当前请求是放在自身对应风格的数组中,close
时要消费下一个等待的请求,同时也不要忘了手动释放资源。
app.js
逻辑部分
const requsetQueue = require('./app/middleware/request-queue');
const app = new Koa();
app.use(requsetQueue({maxReqNumber: 1,apis: ['/api/aigc/image', '/api/aigc/textToImage', '/api/aigc/img2img'],})
);
app.listen(process.env.NODE_ENV === 'development' ? '9527' : '3000');
总结
其实基于 Promise
的 Resolve
队列,我们还可以实现一些其他的功能,比如:前端代码中未登录状态下收集某些请求,等到登录成功后发送请求。也希望大家一起探索和讨论Promise的其他解决能力的实现方案。
- END -
关于奇舞团
奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。
相关文章:

基于Promise.resolve实现Koa请求队列中间件
本文作者为360奇舞团前端工程师 前言 最近在做一个 AIGC 项目,后端基于 Koa2 实现。其中有一个需求就是调用兄弟业务线服务端 AIGC 能力生成图片。但由于目前兄弟业务线的 AIGC 项目也是处于测试阶段,能够提供的服务器资源有限,当并发请求资源…...

【结构型设计模式】C#设计模式之桥接模式
题目:设计一个桥接模式来实现图形和颜色之间的解耦。 解析: 桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立变化。在这个例子中,抽象部分是图形(如圆形、正方形)&am…...

【12】Git工具 协同工作平台使用教程 Gitee使用指南 腾讯工蜂使用指南【Gitee】【腾讯工蜂】【Git】
tips:少量的git安装和使用教程,更多讲快速使用上手Gitee和工蜂平台 一、准备工作 1、下载git Git - Downloads (git-scm.com) 找到对应操作系统,对应版本,对应的位数 下载后根据需求自己安装,然后用git --version验…...

zookeeper增加IP白名单-安全设置
简介: zookeeper未授权访问漏洞,处理这个漏洞最简单,常用的应该就是给zookeeper添加用户名、密码验证,如果项目比较急,且代码不支持zookeeper的用户名、密码验证,那采用ip白名单过滤,无疑是最快…...

Mac 调试 ios safar
1. 打开Mac的 Safari 浏览器的“开发”菜单 运行 Safari 浏览器,然后依次选取“Safari 浏览器”>“偏好设置”,点按“高级”面板,然后勾选“在菜单栏中显示开发菜单”。 2. 开启IPhone的Safari调试模式 启用 Web 检查 功能,打…...

Linu网络服务NFS
linux网络服务NFS 一.NFS简介二.NFS原理三.NFS优势四.配置文件五.NFS共享存储服务的操作步骤 一.NFS简介 NFS(网络文件服务) NFS是一种基于tcp/ip传输的网络文件系统协议,最初由sun公司开放通过使用NFS协议,客户机可以像访问本地…...

24届近5年同济大学自动化考研院校分析
今天给大家带来的是同济大学控制考研分析 满满干货~还不快快点赞收藏 一、同济大学 学校简介 同济大学历史悠久、声誉卓著,是中国最早的国立大学之一,是教育部直属并与上海市共建的全国重点大学。经过115年的发展,同济大学已经…...

多源BFS
多源 超级源点和汇点最短距离[超级汇点]昂贵的聘礼 多源BFS矩阵距离 超级源点和汇点 超级源点跟超级汇点是模拟出来的虚拟点,多用于图中: <1>同时有多个汇点和一个源点,建立超级汇点 1、2、3、6分别到达4或者5或者7的最短路径…...

自制电子农历
水文大师上线。今天一水电子农历牌。 首先讲讲电子配件,一来是电子小屏幕的选择,遇到文字比较多的,尤其是汉字,不要选传统那款128x64 oled,绝对放不下(找到最牛的超小免费字体至少要在8pixel以上才能看清楚)。我选了i…...

解决nvm安装后,node生效但npm无效
问题描述 nvm安装后,node生效但npm无效 清除缓存 C:\Users\cc\AppData\Roaming cc是我的用户名改成你自己的就行删除 npm和npm-cache...

Chrome DevTools 与 WebSocket 数据查看失焦的问题
Chrome DevTools 在与 WebSocket 连接交互时可能会出现失焦的问题,这似乎是一个已知的 bug。当 DevTools 选中 WebSocket 消息时,如果有新的消息到达,DevTools 将会自动失焦,导致无法查看完整的消息内容。 虽然这个问题很令人困扰…...

Javascript 正则
基本语法 定义 JavaScript种正则表达式有两种定义方式 构造函数 var regnew RegExp(<%[^%>]%>,g);字面量 var reg/<%[^%>]%>/g;g: global,全文搜索,默认搜索到第一个结果接停止i:ingore case,忽略…...

C语言可变数组 嵌套的可变数组,翻过了山跨过了河 又掉进了坑
可变数组 专栏内容: postgresql内核源码分析 手写数据库toadb 并发编程 个人主页:我的主页 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物. 概述 数组中元素是顺序存放,这一特性让我们…...

FFmpeg安装和使用
sudo apt install ffmpeg sudo apt-get install libavfilter-devcmakelist模板 CMakeLists.txt cmake_minimum_required(VERSION 3.16) project(ffmpeg_demo)# 设置ffmpeg依赖库及头文件所在目录,并存进指定变量 set(ffmpeg_libs_DIR /usr/lib/x86_64-linux-gnu) …...

HTTP代理编程:Python实用技巧与代码实例
今天我要与大家分享一些关于HTTP代理编程的实用技巧和Python代码实例。作为一名HTTP代理产品供应商,希望通过这篇文章,帮助你们掌握一些高效且实用的编程技巧,提高开发和使用HTTP代理产品的能力。 一、使用Python的requests库发送HTTP请求&a…...

java调用第三方接口工具类 (HttpClientUtils.java)
1. 依赖 <!--httpclient--> <dependency><groupId>commons-httpclient</groupId><artifactId>commons-httpclient</artifactId><version>3.1</version> </dependency><!-- 阿里JSON解析器 --> <dependency>…...

f1tenth仿真设置
文章目录 一、安装依赖二、进入工作空间克隆三、编译四、运行 一、安装依赖 tf2_geometry_msgs ackermann_msgs joy map_server sudo apt-get install ros-noetic-tf2-geometry-msgs ros-noetic-ackermann-msgs ros-melodic-joy ros-noetic-map-server 二、进入工作空间克隆…...

Technical debt (技术负债 / 技术债)
Technical debt (技术负债 / 技术债) In software development, or any other IT field (e.g., Infrastructure, Networking, etc.) technical debt (also known as design debt or code debt) is the implied cost of future reworking required when choosing an easy but li…...

【MATLAB第67期】# 源码分享 | 基于MATLAB的morris全局敏感性分析
【MATLAB第67期】# 源码分享 | 基于MATLAB的morris全局敏感性分析 一、代码展示 clear all npoint100;%在分位数超空间中要采样的点数(计算次数iternpoint*(nfac1) nfac20;%研究函数的不确定因素数量 [mu, order] morris_sa1((x)test_function(x), nfac, npoint)for t1:size…...

ruby send call 的简单使用
refer: ruby on rails - What does .call do? - Stack Overflow Ruby使用call 可以调用方法或者proc m 12.method("") # > method gets the method defined in the Fixnum instance # m.class # > Methodm.call(3) #> 15 # 3 is passed inside the…...

24聊城大学823软件工程考研
1.软件发展有几个阶段?各有何特征? ①程序设计阶段 硬件特征:价格贵、存储容量小、运行可靠性差。 软件特征:只有程序、程序设计概念,不重视程序设计方法。 ②程序系统阶段。 硬件特征:速度、容量及工作可…...

勘探开发人工智能技术:机器学习(3)
0 提纲 4.1 logistic回归 4.2 支持向量机(SVM) 4.3 PCA 1 logistic回归 用超平面分割正负样本, 考虑所有样本导致的损失. 1.1 线性分类器 logistic 回归是使用超平面将空间分开, 一边是正样本, 另一边是负样本. 因此, 它是一个线性分类器. 如图所示, 若干样本由两个特征描…...

定制 ChatGPT 以满足您的需求 自定义说明
推荐:使用 NSDT场景编辑器 快速助你搭建可二次编辑的3D应用场景 20 月 <> 日,OpenAI 宣布他们正在引入带有自定义说明的新流程,以根据您的特定需求定制 ChatGPT。 什么是自定义说明? 新的测试版自定义指令功能旨在通过防止…...

taro h5列表拖拽排序 --- sortablejs 和 react-sortable-hoc
描述:列表,拖拽排序,只测试了h5 一、sortablejs 文档:http://www.sortablejs.com/ 1.安装sortablejs 2、引入 import Sortable from sortablejs3、页面 const [list, setList] useState([{id: item-1,content: 选项1 }, {id…...

Linux的shell脚本常用命令
1、前提 使用shell脚本可以将所要执行的命令行进行汇总,统一执行,制作为脚本工具,简化重复性工作 1.1、常用命令 1.1.1、启动命令 假设我们拥有一个halloWord.sh的脚本,通过cd 命令进入相对应的目录下 ./halloWord.sh1.1.2、…...

使用自己的数据集预加载 Elasticsearch
作者:David Pilato 我最近在讨论论坛上收到一个问题,关于如何修改官方 Docker 镜像以提供一个现成的 Elasticsearch 集群,其中已经包含一些数据。 说实话,我不喜欢这个想法,因为你必须通过提 entrypoint.sh 的分叉版本…...

机器视觉赛道持续火热,深眸科技坚持工业AI视觉切入更多应用领域
随着深度学习等算法的突破、算力的不断提升以及海量数据的持续积累,人工智能逐渐从学术界向工业界落地。而机器视觉作为人工智能领域中一个正在快速发展的分支,广泛应用于工业制造的识别、检测、测量、定位等场景,相较于人眼,在精…...

MyBatis操作数据库常见用法总结2
文章目录 1.动态SQL使用什么是动态sql为什么用动态sql标签拼接标签拼接标签拼接标签拼接标签拼接 补充1:resultType和resultMap补充2:后端开发中单元测试工具使用(Junit框架) 1.动态SQL使用 以insert标签为例 什么是动态sql 是…...

基于SpringBoot+LayUI的宿舍管理系统 001
项目简介 源码来源于网络,项目文档仅用于参考,请自行二次完善哦。 系统以MySQL 8.0.23为数据库,在Spring Boot SpringMVC MyBatis Layui框架下基于B/S架构设计开发而成。 系统中的用户分为三类,分别为学生、宿管、后勤。这三…...

C语言笔记7
#include <stdio.h> int main(void) {int a123;int b052;//十进制42int c0xa2;//十进制162printf("a%d b%o c%x \n",a,b,c);//分别是十进制 八进制 十六进制printf("a%d b%d c%d \n",a,b,c);printf("Hello 凌迟老头\n");return …...