重学 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 定时器能准确输出结果。

相关推荐
老码沉思录30 分钟前
写给初学者的React Native 全栈开发实战班
javascript·react native·react.js
我不当帕鲁谁当帕鲁34 分钟前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂38 分钟前
工程化实战内功修炼测试题
前端·javascript
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新5 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html
Dread_lxy6 小时前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
奔跑草-7 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与7 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
前端郭德纲7 小时前
浏览器是加载ES6模块的?
javascript·算法
JerryXZR7 小时前
JavaScript核心编程 - 原型链 作用域 与 执行上下文
开发语言·javascript·原型模式