土拨鼠日志:任务完成了不响,还显示两遍?
今天有两件小事,都是「明明做好了,界面却跟你说不是」:一个是任务跑完了不响提示音,一个是同一条「等待你确认」在屏幕上躺了两遍,过一会儿下面那张还自己消失了。看着不搭界,根子是同一句话——界面拿到的信号,跟真实发生的事情对不上。
一、提示音时有时无:不是音量问题,是浏览器不让它响
用户的原话是「以前有,现在没了」。我们第一反应是查音频文件、查音量、查静音开关,全都没问题。真正的答案在浏览器的自动播放策略里:
- 网页里的音频要能出声,前提是音频上下文处于
running状态; - 而这个上下文默认是
suspended(暂停)的,只有用户真的点过、按过键,才允许被唤醒; - 任务完成提示恰恰发生在「没人碰电脑」的时候——任务自己在后台跑完,哪来的手势?于是音符被排进了一个永远冻结的时钟里,静悄悄地不响。
更隐蔽的是第二层:原来的代码调了 resume() 之后就不管了,直接往下排音符。可 resume() 是异步的,唤醒还没完成,音符已经排完了。两层叠在一起,结果就是「有时候响、大多数时候不响」——恰恰是最难复现、最容易被当成玄学的那种故障。
二、修法:等它真的醒了,再放声音
改法不复杂,但两处都得改,缺一处就还是哑的:
- 先等唤醒,再排音符:把「排音符」放进唤醒成功的回调里,并且再确认一次状态确实是
running才排,避免唤醒失败时排出一串「迟到的鬼铃声」; - 给页面装一个一次性解锁器:用户第一次点窗口或按键时,悄悄把音频上下文唤醒。此后哪怕任务是在无人操作时跑完的,也能正常出声。
顺带把「什么时候该响」也收紧了:只在真的产出一条新结果时响、只对两分钟内的新鲜结果响、同一个会话 30 秒内最多响一次。刷新页面不会变成一片铃铛雨。
三、同一条「等待确认」显示两遍,还自己少一张
第二个问题更典型。截图里同一句「等待你确认」加三行待办,屏幕上出现了两遍;过一会儿下面那一份自己消失了。
查下来,这两份根本不是「同一个东西渲染了两次」,而是两个不同的来源各画了一份:
- 上面那份是消息正文本身,属于持久内容,刷新、重连都还在;
- 下面那份是按状态轮询动态插进去的浮动提示卡,状态一抖(重渲染、真实状态刷新、下一轮开始)它就被判定为「不需要了」,于是自己删掉——这就是「过一会儿少一个」的原因。
这类问题的坑在于:两个来源单独看都合理,合起来就是「重复 + 闪烁」。修的时候不能只把浮动卡藏掉,否则碰上「正文没写、但确实在等」的情况,用户就什么提示都看不到了。
所以我们用的是判重而不是删除:插卡之前先看正文末尾有没有已经写了等待字样、而且内容能对上这次要问的事;能对上就不插卡,顺手把多余的角标收掉;对不上(正文没写,或者写的是另一件事)才保留浮动卡兜底。
四、这两件事教给我们的一条通用规矩
提示音和重复气泡,其实都在讲同一件事:别让「看起来正常」代替「真的正常」。
- 声音:不要以为调了唤醒就等于唤醒了,要看状态真的变成
running; - 状态:不要以为读到了一个值就等于读到了真相,要区分「初始默认值」和「探测通过」;
- 同一个信息,只允许有一个权威来源,多出来的那个只能兜底,不能跟主源平起平坐。
这套思路在土拨鼠里是硬要求:状态没探测出来就老实写「尚未就绪」,探测通过才写「正常」,绝不用一个好看的初始值糊过去。你在 功能页 能看到任务状态与自动化这块怎么落地;想先算算成本,定价页 有按量账本;想自己上手试,直接 下载 装一个,跑两个长任务看看它到底响不响。
五、一个 30 秒自查
下次遇到「该响的不响 / 该有的显示两遍」,按顺序问三句:
- 触发这件事的时候,页面有没有拿到用户的真实操作?(很多能力没手势就是不给用)
- 那个异步调用,我是「发了就不管」,还是等它真的成功才继续?
- 屏幕上重复的这两份,是不是来自两个不同的渲染源?删之前有没有想清楚谁该留?
中任意一条,基本就能解释大半「它怎么又抽风了」。界面最贵的 bug,从来不是崩掉,而是安静地骗你。
土拨鼠 Marmot