页面用 setTimeout 做过期提醒,延时设成 30*24*3600*1000,结果回调立刻就跑了。控制台只有一条 TimeoutOverflowWarning,没有报错。第一次遇到会往复杂处想,其实漏掉的多是个小前提。
node -e "console.log(30*24*3600*1000, 2**31-1)"
node -e "setTimeout(()=>console.log('fired'), 2592000000)"
浏览器把延时值当 32 位有符号整数处理,超过 2147483647 会溢出成负数,负数按 0 处理,回调排进下一个事件循环。30 天是 2592000000,正好越界。这一点先确认清楚,后面就不用反复试。
「setTimeout 溢出」这类改动最怕改一半,回滚脚本先准备好,再动生产。把复现步骤压到三条以内,交给同事也能跑出来,才算真的定位清楚。
改动写完就同步给同事,下一个人踩同一个坑,成本还是你的。验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。
具体做法是,长延时拆成多段 每次最多一天 到期再续;用服务端下发的过期时间加轮询校正;延时值封顶判断 超过上限走降级;后台标签页的定时器会被节流 不能当闹钟。
改完照着核一遍,改成分段延时后 30 天的提醒不会立刻弹出 到点才触发。
