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

相关推荐
fishmemory7sec1 分钟前
Electron 使⽤ electron-builder 打包应用
前端·javascript·electron
JUNAI_Strive_ving1 小时前
番茄小说逆向爬取
javascript·python
看到请催我学习1 小时前
如何实现两个标签页之间的通信
javascript·css·typescript·node.js·html5
twins35202 小时前
解决Vue应用中遇到路由刷新后出现 404 错误
前端·javascript·vue.js
qiyi.sky2 小时前
JavaWeb——Vue组件库Element(3/6):常见组件:Dialog对话框、Form表单(介绍、使用、实际效果)
前端·javascript·vue.js
煸橙干儿~~2 小时前
分析JS Crash(进程崩溃)
java·前端·javascript
哪 吒2 小时前
华为OD机试 - 几何平均值最大子数(Python/JS/C/C++ 2024 E卷 200分)
javascript·python·华为od
安冬的码畜日常2 小时前
【D3.js in Action 3 精译_027】3.4 让 D3 数据适应屏幕(下)—— D3 分段比例尺的用法
前端·javascript·信息可视化·数据可视化·d3.js·d3比例尺·分段比例尺
Q_w77423 小时前
一个真实可用的登录界面!
javascript·mysql·php·html5·网站登录
昨天;明天。今天。3 小时前
案例-任务清单
前端·javascript·css