Promise本身不是防重工具,但可通过pendingPromise实现提交锁:所有点击等待同一Promise,首次执行请求,后续直接返回该Promise;需绑定form submit事件、阻止默认行为、恢复按钮状态,并配合服务端幂等设计。

Promise 本身不是防重工具,但它能帮你把“只允许一次提交”这个逻辑自然地串起来——关键不在 Promise 多强大,而在你用它管住状态、复用请求、避免并发发起多个相同操作。
用 pendingPromise 实现提交锁
核心思路是:让所有点击都等待同一个 Promise,而不是各自发请求。首次点击真正执行提交;后续点击直接返回那个正在跑的 Promise。
- 声明一个共享变量(如 let pendingSubmit = null)
- 每次调用提交函数时,先检查 pendingSubmit 是否存在;有就直接返回它
- 没有则创建新请求,并把返回的 Promise 赋给 pendingSubmit
- 请求结束(无论成功失败)后,可选择重置 pendingSubmit = null,为下一次提交做准备
结合表单 submit 事件统一拦截
只监听按钮 click 容易漏掉回车提交或脚本调用,正确做法是绑定在 form 的 submit 事件 上,并立刻阻止默认行为:
- 在事件回调里先 e.preventDefault()
- 再判断或生成 pendingPromise,确保所有提交路径都走同一套逻辑
- 提交完成后,记得恢复按钮可用性(尤其失败时),否则用户无法重试
封装成可复用的 submitOnce 函数
把逻辑抽出来,方便多个表单复用:
立即学习“Java免费学习笔记(深入)”;
- 接收表单元素和提交函数(如 fetch 或 axios 调用)
- 内部维护自己的 pendingPromise 和重置机制
- 返回一个函数,调用即触发带锁提交,且自动处理禁用/启用按钮、错误恢复等细节
别忘了配合服务端幂等设计
前端 Promise 锁解决的是“用户连点”带来的瞬时并发,但绕过页面(如 Postman 直发)、刷新重提、网络重试等问题仍需后端兜底:
- 每个请求带唯一 token,服务端校验并标记已处理
- 关键操作加数据库唯一索引(如订单号)或乐观锁版本号
- 接口设计为幂等:相同参数多次调用,结果一致且无副作用


















