『问题探究』递归调用 setTimeout 和 setInterval 的区别

392 阅读1分钟

前几天在快手校招三面中被问到了这样一道题:

请给出输出结果:

  function interval() {
    setTimeout(() => {
      console.log(1);
      interval();
    }, 10);
  }

  interval();

  setInterval(() => {
    console.log(2);
  }, 10);

我虽然学过事件循环,知道它们都是宏任务,但是这个场景以前没研究过,不知道这俩到底有什么区别,于是不假思索回答“1212反复出现”。然后面试官给我说它们有细微区别...

刚才在看现代JavaScript教程的时候看到了相关内容,恍然大悟,在此处记录一下。

这两张图都来自教程,这是setInterval:

image.png

这是setTimeout:

image.png

有了这个差异,如果同时存在interval和递归调用的timeout,在传入的“间隔”相同的情况下,它们的执行顺序绝对不是交替的。

如果把回调函数从第一次开始执行到第二次开始执行的时间定义为一个周期,显然interval的周期等于“间隔”,而timeout的周期等于“间隔 + 回调执行时间”。因为interval的周期短,所以随着时间流逝,interval的执行次数实际上是大于timeout的。

可以计算出,interval的执行频率和timeout的执行频率之比 = 1 + 回调执行时间 / 间隔。假设回调函数执行的时间不变,“间隔”越短,interval相对timeout,执行的次数就越多。

同样是一开始的那段代码,当time === 50ms时,控制台是这样的:

image.png

而改成10ms,就会变成这样:

image.png

就是这样。