重复使用setTimeout

64

我试图每隔10秒重复执行setTimeout。我知道setTimeout默认只等待一次然后执行一次操作。我该如何重复这个过程?

setTimeout(function() {
  setTimeout(function() {
    console.log("10 seconds");
  }, 10000);
}, 10000);

这个问题可能与此相关:https://dev59.com/LnA75IYBdhLWcg3wubqn - Anderson Green
7个回答

102

12
一些可能有用的附加文档:https://developer.mozilla.org/en/DOM/window.setInterval - vcsjones
哈哈,啊好的,谢谢。我没意识到setInterval和setTimeout都有延迟。 - Daniel
6
你甚至没有提供替代方案。有理由使用重复的setTimeout而不是setInterval。你只是陈述了显而易见的事实,这很好,因为有时候它并不显而易见,但没有真正回答原始问题。 - NonameSL

54

setInterval()可能是你要找的,但如果你想使用setTimeout()来达到相同的效果:

setInterval()很可能是您正在寻找的内容,但如果您想要使用setTimeout()获得相同的效果:

function doSomething() {
    console.log("10 seconds");
    setTimeout(doSomething, 10000);
}

setTimeout(doSomething, 10000);

或者,如果您不想声明单独的函数并希望坚持使用函数表达式,则需要将其变成命名函数表达式:

setTimeout(function doSomething() {
    console.log("10 seconds");
    setTimeout(doSomething, 10000);
}, 10000);

(或者使用 arguments.callee ,如果您不介意使用被弃用的语言特性。)


不要使用 arguments.callee,因为它会降低性能,而是给你的函数命名,然后使用该名称。当然,这在IE中不起作用,但我认为这是一个很好的折衷方案。 - Aadit M Shah
1
@AaditMShah,你说的“在IE中不起作用”是什么意思?命名函数表达式在IE中与其他浏览器不同(甚至有缺陷),但它们肯定是“可行的”。 - RobG
@AaditMShah - 我同意RobG的看法。但是,假设它在IE中根本不起作用,忽略一个有着巨大市场份额的浏览器怎么能是一个“好的妥协”呢?无论如何,你可以看到我只是把arguments.callee作为想法的补充:我主要包括它是为了链接到MDN上关于递归函数表达式的讨论页面。你真的认为你提到的性能降低会在10秒延迟或任何基于超时的算法中产生影响吗?这些算法实际上并不是真正的递归吗? - nnnnnn
@nnnnnn - 这与递归无关。使用arguments.callee使解释器难以内联函数。在这种情况下,它肯定不会有太大的影响,但在关键位置(例如运行在60 fps的游戏循环中),它肯定会导致延迟。此外,命名函数表达式看起来更清晰,我不太关心旧版本的IE。它们甚至无法运行HTML5游戏。较新版本最终开始符合标准。 - Aadit M Shah

20

根据我的看法,setInterval() 是您的最佳选择。
以下是一些代码:

 setInterval(function() {

//your code

}, 10000); 
// you can change your delay by changing this value "10000".

2
请注意,这将安排函数体在从调用setInterval方法开始的10000毫秒延迟后执行。 - ad4s
请提供一个解释。 - fourk

19

与@nnnnnn和@uzyn提供的答案不同,我不建议您使用setInterval,原因在以下答案中有详细解释。相反,请使用以下Delta Timing脚本:

function DeltaTimer(render, interval) {
    var timeout;
    var lastTime;

    this.start = start;
    this.stop = stop;

    function start() {
        timeout = setTimeout(loop, 0);
        lastTime = + new Date;
        return lastTime;
    }

    function stop() {
        clearTimeout(timeout);
        return lastTime;
    }

    function loop() {
        var thisTime = + new Date;
        var deltaTime = thisTime - lastTime;
        var delay = Math.max(interval - deltaTime, 0);
        timeout = setTimeout(loop, delay);
        lastTime = thisTime + delay;
        render(thisTime);
    }
}
上述脚本尽可能地接近指定的间隔运行给定的render函数,并且为了回答您的问题,它利用setTimeout来重复一个过程。 在您的情况下,您可以执行以下操作:
var timer = new DeltaTimer(function (time) {
    console.log("10 seconds");
}, 10000);

var start = timer.start();

你的函数没有按照你想象的那样运行。loop 在第一次之后以零的时间间隔被调用。 - RobG
@RobG - 我不太同意。当你调用 start 时,它首先以 0 毫秒的延迟调用循环。然而,浏览器通常指定最小延迟为 4 毫秒。之后,它会调整延迟,使其始终在固定时间间隔内调用。你不需要相信我的话。请参见以下 fiddle,它记录了计时器开始每秒的时间差异。 - Aadit M Shah
将您的代码复制并粘贴到IE 8中(并将Date.now替换为new Date(),因为非ES5浏览器不支持它)会导致在第一次调用后立即运行函数,而不是等待。 - RobG
1
好的,问题已找到。在IE 8中,除了将Date.now替换为new Date()之外,您还需要使用lastTime = new Date(thisTime.getTime() + delay);作为答案中的行会导致NaN。顺便说一下,这些更改也应该适用于其他浏览器。您需要进行更广泛的测试。否则,您的答案很好。 - RobG
@RobG - 我可以这样做,也可以搜索并替换所有的 Date.now()+ new Date。两者都是一样的。 - Aadit M Shah
@RobG - 我已经做出了更改。请查看此fiddle,以确认它现在是否可以在IE中正确运行。 - Aadit M Shah

3
const myFunction = () => {
        setTimeout(() => {
            document.getElementById('demo').innerHTML = Date();
            myFunction();
        }, 10000);
    }

最简单但不是最高效的方式!

0
这里有一个使用setTimeout函数的函数,它试图尽可能接近常规间隔调用自身。如果您观察输出,您会看到时间在漂移并被重置。
<script type="text/javascript">

function Timer(fn, interval) {
  this.fn = fn;
  this.interval = interval;
}

Timer.prototype.run = function() {

    var timer = this;
    var timeDiff = this.interval;
    var now = new Date();  // Date.now is not supported by IE 8
    var newInterval;

    // Only run if all is good
    if (typeof timer.interval != 'undefined' && timer.fn) {

      // Don't do this on the first run
      if (timer.lastTime) {
        timeDiff = now - timer.lastTime;
      }
      timer.lastTime = now;

      // Adjust the interval
      newInterval = 2 * timer.interval - timeDiff;

      // Do it
      timer.fn();

      // Call function again, setting its this correctly
      timer.timeout = setTimeout(function(){timer.run()}, newInterval);
  }
}


var t = new Timer(function() {
  var d = new Date();
  document.getElementById('msg').innerHTML = d + ' : ' + d.getMilliseconds();
}, 1000);


window.onload = function() {
  t.run();
};
</script>

<span id="msg"></span>

-1

使用jQuery,您可以这样做:

function updatePage() {

var interval = setTimeout(updatePage, 10000); // 10' Seconds

    $('a[href]').click(function() {
      $(this).data('clicked', true);
      clearInterval(interval); // Clears Upon Clicking any href Link
      console.log('Interval Cleared!');
    });
   // REPLACE 'YOUR_FUNCTION_NAME' function you would like to execute
    setTimeout(YOUR_FUNCTION_NAME, 500);

} // Function updatePage close syntax

updatePage(); // call the function again.


1
我认为你应该编辑代码,这样它就不会每500毫秒抛出错误了。 - fourk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接