注意, setTimeout 有最大延时值, 溢出就会被立即执行
我们有时候使用 setTimeout
会简单粗暴地使用外部传入的值, 如下:
async function sleepMs(ms: number) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
这样通常情况下没问题, 但是如果输入的数值过大, 会出现意想不到的 bug.
我们知道 js 中, Number.MAX_SAFE_INTEGER 是 2^53 - 1
, 但是 setTimeout
并不支持那么大的数。
浏览器内部以 32 位带符号整数存储延时。这就会导致如果一个延时大于 2147483647 (即 2^31 - 1) 毫秒(大约 24.8 天)时就会溢出,导致定时器将会被立即执行。
所以, 如果数值是外部传入的, 建议函数内做一个简单的判断 (过滤):
async function sleepMs(ms: number): Promise<void> {
// 至于如何处理 NaN, 则可以根据业务, 自己决定是抛错还是赋默认值
if (Number.isNaN(ms)) {
throw new Error("invalid input: NaN");
}
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, clamp(ms, 0, 2 ** 31 - 1));
});
}