注意, setTimeout 有最大延时值, 溢出就会被立即执行

我们有时候使用 setTimeout 会简单粗暴地使用外部传入的值, 如下:

async function sleepMs(ms: number) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

这样通常情况下没问题, 但是如果输入的数值过大, 会出现意想不到的 bug.

我们知道 js 中, Number.MAX_SAFE_INTEGER2^53 - 1, 但是 setTimeout 并不支持那么大的数。

https://developer.mozilla.org/zh-CN/docs/Web/API/setTimeout#%E6%9C%80%E5%A4%A7%E5%BB%B6%E6%97%B6%E5%80%BC

浏览器内部以 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));
  });
}

如非特别声明,本站作品均为原创,遵循【自由转载-保持署名-非商用-非衍生 创意共享 3.0 许可证】。

对于转载作品,如需二次转载,请遵循原作许可。