重学 setTimeout

html.spec.whatwg.org/multipage/t...

这是最新关于 setTimeout 的标准。

1. 简单使用

js 复制代码
setTimeout(() => {
  console.log("回调了")
}, 0)

0ms 后执行回调。其中第二个参数的单位是 ms ,所以要想在 1s 内执行回调,那么就传递 1000 即可。

2. 函数定义和说明

我们看看 setTimeout 的函数定义( Web IDL ):

c++ 复制代码
long setTimeout(TimerHandler handler, optional long timeout = 0, any... arguments);

具体解释一下每一个参数的含义:

  • handler TimerHandler 类型,也就是回调函数,或者字符串。
c++ 复制代码
typedef (DOMString or Function) TimerHandler;

当是字符串的时候代表 code ,也就是到时间会执行字符串代码:

js 复制代码
function test() {
  console.log("Hello wujingyue.")
}
setTimeout("test()", 10)
// 会打印: Hello wujingyue.
  • timeout 超时的时间,默认为 0 ,是一个可选的参数。
  • arguments 可选的参数,用于传递给 handler 参数的,在有一些情况下,比如:
js 复制代码
function test(name) {
  console.log(`我的名字是:${name}`)
}
setTimeout(test, 0, "吴敬悦")

其中"吴敬悦"就会传递给 test 函数,这样我们不用再写回调了。

3. 消除之前的理解

消除之前的理解,我们可以在 6.3 Timers --- HTML5 上看到下面这句话:

If the currently running task is a task that was created by the setTimeout() method, and timeout is less than 4, then increase timeout to 4.

如果当前正在运行的任务是通过setTimeout()方法创建的任务,并且超时时间小于4,则将超时时间增加到4。

也就是当我们的参数 timeout 小于 4 的时候,就会将 timeout 设置成 4 。现在的标准中已经不是这样的了,而且目前我的 chrome v122.0.6261.70 版本也已经改成最新标准的实现了,而不是上面描述的这种实现。下面我们验证一下:

js 复制代码
const startTime = Date.now()
function test(name) {
  console.log(Date.now() - startTime) // 3
}
setTimeout(test, 0)

首先我们知道这里的这个时间不一定准确,至于原因在标准中也说明了。

This API does not guarantee that timers will run exactly on schedule. Delays due to CPU load, other tasks, etc, are to be expected.

该API不能保证定时器会准确按计划运行。由于CPU负载、其他任务等造成的延迟是可以预料的。

当有一点我们是清楚的,也就是上面的打印小于 4 了,说明小于4就设置成4的结论是错误的。在我的电脑上测试,其实出现小于 4 的情况是不常见的,但只要出现过就足以说明了。

虽然只有一层不会出现小于 4 就自动设置成 4 的情况,但是如果你的嵌套层级大于 5 ,那么就会使用上面的规则。

js 复制代码
setTimeout(() => {
  // 第一层嵌套
  setTimeout(() => {
    // 第二层嵌套
    setTimeout(() => {
      // 第三层嵌套
      setTimeout(() => {
        // 第四层嵌套
        setTimeout(() => {
          // 第五层嵌套
          setTimeout(() => {
            // 第六层嵌套
            // 这里的 timeout 如果设置的是小于 4 的数,那么就会设置成 4
            // 我这里写的是 0 ,会被改成 4 ,这里规则是大于 5 层嵌套都会这样
          }, 0)
        }, 0)
      }, 0)
    }, 0)
  }, 0)
}, 0)

具体可以验证一下,你会发现大于 5 层所执行的时间不会小于 4 。这个规则具体看标准中的第五条。

If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4.

如果嵌套级别大于5,并且超时时间小于4,则将超时时间设置为4

4. 有趣的代码

js 复制代码
var log = '';
function logger(s) { log += s + ' '; }

// 1 层 setTimeout
setTimeout({ toString: function () {
  // 2 层 setTimeout
  setTimeout("logger('ONE')", 100);
  return "logger('TWO')";
} }, 100);

setTimeout(() => {
  console.log(log) // ONE TWO
}, 101)

我们看到这里传入的是对象;像这样的代码 setTimeout 在执行的时候会先对传入的参数进行 toString ,当然前提是传入的类型是数组,对象这样的引用类型。上面代码的执行顺序是:

注意虽然这里写了两个大约 100ms 后,但实际情况是这两个 100ms 是并行的,所以我下面的 101 定时器能准确输出结果。

相关推荐
薛定猫AI6 小时前
【深度解析】Gemma Chat 本地 AI 编程 Agent:Electron + MLX + 开源模型的离线 Vibe Coding 实战
javascript·人工智能·electron
全栈前端老曹7 小时前
【前端地图】多地图平台适配方案——高德、百度、腾讯、Google Maps SDK 差异对比、封装统一地图接口
前端·javascript·百度·dubbo·wgs84·gcj-02·bd09
笑虾7 小时前
Win10 修改注册表 让鼠标悬停PNG上时 tip 始终显示分辨率
开发语言·javascript·ecmascript
雾岛听风6917 小时前
JavaScript基础语法速查手册
开发语言·前端·javascript
用户2367829801688 小时前
从零实现 GIF 制作工具:LZW 压缩与 Median Cut 色彩量化
前端·javascript
棉猴8 小时前
Python海龟绘图之绘制文本
javascript·python·html·write·turtle·海龟绘图·输出文本
Highcharts.js8 小时前
线形比赛积分增长或竞赛图|Highcharts企业图表代码示列
开发语言·前端·javascript·折线图·highcharts·竞赛图
让学习成为一种生活方式9 小时前
大肠杆菌合成扑热息痛--对乙酰氨基酚--文献精读227
开发语言·前端·javascript
多秋浮沉度华年9 小时前
electron 初始使用记录
javascript·arcgis·electron
竹林8189 小时前
用 wagmi v2 + WebSocket 硬磕 NFT 上架失败:一个前端开发者踩过的实时状态同步坑
javascript·next.js