摘要
在 page.ts 事件 handler 中,若 FeedBack.openLoading() 与 closeLoading() 之间没有真实异步 await,会出现两类问题:
- Loading 遮罩与按钮点击动画完全不生效(不是播得太短,而是整段反馈缺失)。
- 用户快速连点时,handler 会被多次执行,导致重复
append、重复汇总等业务副作用。
在中间插入任意真实 await(如无关的 model.get)后,Loading 正常显示、连点问题随之缓解——说明根因在平台反馈/遮罩机制,而非业务逻辑本身。
出现条件
同时满足以下情况时复现:
| # | 条件 |
|---|---|
| 1 | 在 subscribeEvent 的 async handler 内调用 FeedBack.openLoading() |
| 2 | openLoading 与 closeLoading 之间无真实异步等待(仅同步 append、字段赋值、Modal.close(),或 await 的函数体内无 I/O) |
| 3 | Handler 在同一轮事件循环内很快结束并调用 closeLoading() |
不出现的情况:中间存在真实异步,例如 await Table5.call(...)、await model.get(...)、await service.*(...)。
现象
1. 视觉反馈完全缺失
- 全局 Loading 不显示
- 按钮点击动画 不播放
- 用户感知为「点了没反应」
2. 快速连点导致逻辑重复执行
因 Loading 未真正挂载/遮罩未生效,按钮在 handler 执行期间仍可继续点击。用户连点或误以为未响应再次点击时,同一事件会并发或连续触发多次,例如:
- 子表
fe12重复 append 相同明细 totalAmountOfVolume()重复汇总(数值被放大)- 弹窗可能多次
close()(表现不稳定)
这与「有 Loading 正常工作时」的用户体验形成鲜明对比:Loading 生效时,遮罩会阻断二次操作。
复现案例
元素:workflows.listOfDocumentsApproval
页面:workflows/listOfDocumentsApproval/pages/NodePage/page.ts
事件:Table5 → clickDtKjbS(库存明细弹窗确认添加)
问题写法(去掉 workaround 后):
this.Table5.subscribeEvent("clickDtKjbS", async () => {
this.app.modules.FeedBack.openLoading("正在添加出库明细...");
this.approveForm.formData.fe12.append(/* convertRowList 同步追加 */);
await this.totalAmountOfVolume(); // 无真实 I/O
this.Modal4.close();
this.app.modules.FeedBack.closeLoading();
});
步骤:
- 打开出库单审批 → 子表 → 库存明细弹窗。
- 勾选行,快速连点确认按钮 2~3 次。
- 观察子表:同一批明细可能被重复添加;全程无 Loading、无按钮动画。
对照(插入无关 await get 后):
const RowData1 = Jit.datatypes.RowData(
await this.app.models.salesOrders.get(null, null, 2),
{ "generic": "models.salesOrders", "title": "单行数据1" }
);
- Loading 与按钮动画正常
同页正常对照:clickrAXhdb 中间有 await this.Table5.call(...),无上述问题。
预期 vs 实际
| 预期 | 实际(问题路径) | |
|---|---|---|
| Loading | openLoading() 后立即显示遮罩 |
完全不显示 |
| 按钮反馈 | 点击有动画 | 完全不播放 |
| 防重复 | Loading 期间按钮应被遮罩/禁用 | 可继续点击,逻辑多次执行 |
| 数据 | 一次点击只追加一批明细 | 连点可重复 append |
业务影响
- 出库明细可能被重复添加,汇总金额/数量错误。
- 用户因无反馈而反复点击,放大问题。
- 业务被迫写无意义的
model.get作为 workaround,增加维护成本与无效请求。
根因推测(供平台排查)
FeedBack.openLoading() 可能仅更新状态,未让出渲染、未挂载遮罩;handler 同步结束后立刻 closeLoading(),UI 来不及绘制。遮罩未生效时,无法拦截连点,导致 handler 重复进入。
建议修复
openLoading内部:状态更新后保证至少一次渲染让出(nextTick/rAF),并同步挂载可拦截操作的遮罩。- 事件层:对 Table/按钮在 handler 执行期间提供防重复触发(与 Loading 状态绑定)。
- 文档:在
open-close-loadingpattern 中说明:纯同步逻辑下 Loading 不生效,且存在重复执行风险。
当前 workaround(临时)
在 openLoading 与 closeLoading 之间保留一次真实 await(如无关 salesOrders.get),借异步间隙让 Loading 显示并阻断连点。