Express待办应用高频POST请求致页面卡顿,如何用队列处理?
问题分析与解决方案
卡顿的核心原因
- 客户端重复请求轰炸:每次操作立刻发起POST请求,短时间内5-6次请求同时触发,浏览器并发连接池被占满,导致页面资源调度卡顿。
- MongoDB操作冗余:当前用
findOne + save的方式更新,每次更新要先查询再写入,两次IO操作,连续触发时数据库压力陡增。 - 无请求去重/合并:连续操作其实只需要保存最终的待办状态,中间的多次更新都是无效的,白白消耗资源。
解决方案一:客户端先做请求合并(最快见效)
给sendData加防抖逻辑,让连续操作只发送最后一次的状态,避免无效请求:
// 防抖定时器变量 let debounceTimer = null; function sendData(obj) { // 取消之前未发送的请求 if (debounceTimer) clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { fetch('/jsondata', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(obj), }).catch(error => console.log(error)); console.log('db updated'); }, 300); // 300ms内的连续操作合并成一次请求 }
还可以加上AbortController取消未完成的请求,避免旧请求覆盖新状态:
let abortController = null; let debounceTimer = null; function sendData(obj) { // 取消之前的请求和定时器 if (abortController) abortController.abort(); if (debounceTimer) clearTimeout(debounceTimer); abortController = new AbortController(); debounceTimer = setTimeout(() => { fetch('/jsondata', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(obj), signal: abortController.signal }).catch(error => { if (error.name !== 'AbortError') console.log(error); }); console.log('db updated'); }, 300); }
解决方案二:服务端用队列异步处理
如果必须保留每次操作的记录(或者防抖满足不了需求),可以用消息队列把更新任务异步化,让接口快速返回,后台慢慢处理更新:
- 先安装队列库,比如
bull:
npm install bull
- 配置队列并修改接口:
const Queue = require('bull'); // 创建用户缓存更新队列 const updateCacheQueue = new Queue('user-cache-update'); // 处理队列任务 updateCacheQueue.process(async (job) => { const { email, newState } = job.data; // 用updateOne直接更新,比findOne+save高效 await user.updateOne( { email: email }, { $set: { cachedState: newState, date: Date.now() } }, { upsert: true } // 防止用户不存在的情况 ); console.log('user cache has been updated'); }); // 修改接口,把任务丢进队列就返回 app.post('/jsondata', function (req, res) { updateCacheQueue.add({ email: currentUserEmail, newState: JSON.stringify(req.body) }, { // 同一个用户的任务,保留最新的即可,替换旧任务 jobId: `user-cache-${currentUserEmail}`, removeOnComplete: true, removeOnFail: true }); res.sendStatus(202); // 快速返回接受状态 });
解决方案三:MongoDB操作优化
不管用不用队列,都应该优化数据库操作,把findOne + save改成updateOne,减少一次IO:
async function updateUserCache(email, newState) { await user.updateOne( { email: email }, { $set: { cachedState: newState, date: Date.now() } }, { upsert: true } // 可选,根据你的业务是否需要自动创建用户 ); console.log('user cache has been updated'); }
另外给email字段加索引,加快查询速度:
// 在用户模型里添加索引 userSchema.index({ email: 1 });
内容的提问来源于stack exchange,提问作者Jeff Froehlich
相关产品推荐
相关产品推荐

