E1.17.1shared submit lock across channels设计研究

同时存在点击提交与回车提交时需要共用同一把锁

别名: 回车重复提交 · 双通道锁 · click and enter lock

概念解释

表单往往既能点按钮提交,也能在字段里按回车提交。两通道若各绑各的处理函数,各有一把「进行中」旗标,就会在同一瞬间各发一次。共用同一把锁指:无论点击还是回车,先抢同一把进程内锁,抢不到的那次直接丢掉。只把按钮设为 disabled 却不挡住表单的 submit 事件,回车仍能再送一封。

机制

浏览器默认:焦点在单行输入里按回车,触发表单 submit,再点到提交按钮上。用户的习惯是填完回车,或填完再点,或回车同时鼠标已经在点——后一种在慢响应时尤其多。若点击路径在按钮上锁,回车路径走 form.onsubmit 且不看那把锁,两条路径就是两次请求。键盘重复(按住回车)还会在锁生效前打出一串 keydown。锁必须在所有入口的最前面,而且是同步的:用「等 setState 再禁用」会把锁推迟到下一帧,回车已经出去了。服务端去重是后盾,但客户端双通道仍会制造双倍负载和短暂的双成功态。

怎么研究

在带可调延迟的表单上,同时点按钮并按回车,或按住回车。记录请求条数。对照:只锁按钮、锁按钮且 preventDefault submit、入口函数最前面一把同步锁。

自变量:锁放在哪一层、是否 preventDefault、输入法回车是否另发事件。 因变量:每意图请求数、双成功提示。

自动化分别测 click 和 keydown 会都通过。必须在同一时刻叠加两条通道。

边界

多提交按钮的表单(保存草稿 / 发布)不能共用到「整页一把锁」把另一意图也锁死,但同一意图的所有入口仍要共锁。对话框里回车等于点默认按钮,这是第三条通道,也要进同一把锁。无表单的 div 按钮没有 submit 事件,回车通道可能根本不存在,问题缩小到按钮自己的键与点击。

怎么落地

  • 把发出请求的函数做成单入口,点击、回车、submit 都调用它,函数第一行同步抢锁。
  • 在 form submit 上 preventDefault,避免浏览器再走一遍原生提交。
  • 不要只靠下一帧的 disabled 挡回车。
  • 验证:焦点在输入框时按住回车并同时点击提交。网络日志里这一意图只能有一条请求。

延伸

  • 同组E1.17.2 触屏上的点击延迟可能让两次快速点击都被判定为有效 · E1.17.3 网络失败后需要解锁按钮并呈现明确的错误状态 · E1.17.4 乐观更新场景下按钮解锁时机与结果反馈时机可能不同步
  • 相邻E1.09 加载中按钮 · C6 键盘与文本输入 · H1 表单
  • 站内检索double submit · form submit · Enter key

同组卡片

快捷操作

分享

分享当前页面

ios_share

https://hci.top/zh/handbook/E1.17.1