setTimeout or setInterval?

2018-12-31 00:11发布

As far as I can tell, these two pieces of javascript behave the same way:

Option A:

function myTimeoutFunction()
{
    doStuff();
    setTimeout(myTimeoutFunction, 1000);
}

myTimeoutFunction();

Option B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

Is there any difference between using setTimeout and setInterval?

19条回答
心情的温度
2楼-- · 2018-12-31 00:47

It would probably better to replace the first function by this

Options A'

function myTimeoutFunction()
{
     setTimeout(myTimeoutFunction, 1000);// At first 
     doStuff();
}
myTimeoutFunction();

Isn't it ?

查看更多
像晚风撩人
3楼-- · 2018-12-31 00:48

The setInterval makes it easier to cancel future execution of your code. If you use setTimeout, you must keep track of the timer id in case you wish to cancel it later on.

var timerId = null;
function myTimeoutFunction()
{
    doStuff();
    timerId = setTimeout(myTimeoutFunction, 1000);
}

myTimeoutFunction();

// later on...
clearTimeout(timerId);

versus

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
var timerId = setInterval(myTimeoutFunction, 1000);

// later on...
clearInterval(timerId);
查看更多
皆成旧梦
4楼-- · 2018-12-31 00:48

Your code will have different execution intevals, and in some projects, such as online games it's not acceptable. First, what should you do, to make your code work with same intevals, you should change "myTimeoutFunction" to this:

function myTimeoutFunction()
{
    setTimeout(myTimeoutFunction, 1000);
    doStuff();
}
myTimeoutFunction()

After this change, it will be equal to

function myTimeoutFunction()
{
    doStuff();
}
myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

But, you will still have not stable result, because JS is single-threaded. For now, if JS thread will be busy with something, it will not be able to execute your callback function, and execution will be postponed for 2-3 msec. Is you have 60 executions per second, and each time you have random 1-3 sec delay, it will be absolutely not acceptable (after one minute it will be around 7200 msec delay), and I can advice to use something like this:

    function Timer(clb, timeout) {
        this.clb = clb;
        this.timeout = timeout;
        this.stopTimeout = null;
        this.precision = -1;
    }

    Timer.prototype.start = function() {
        var me = this;
        var now = new Date();
        if(me.precision === -1) {
            me.precision = now.getTime();
        }
        me.stopTimeout = setTimeout(function(){
            me.start()
        }, me.precision - now.getTime() + me.timeout);
        me.precision += me.timeout;
        me.clb();
    };

    Timer.prototype.stop = function() {
        clearTimeout(this.stopTimeout);
        this.precision = -1;
    };

    function myTimeoutFunction()
    {
        doStuff();
    }

    var timer = new Timer(myTimeoutFunction, 1000);
    timer.start();

This code will guarantee stable execution period. Even thread will be busy, and your code will be executed after 1005 mseconds, next time it will have timeout for 995 msec, and result will be stable.

查看更多
有味是清欢
5楼-- · 2018-12-31 00:49

They essentially try to do the same thing, but the setInterval approach will be more accurate than the setTimeout approach, since setTimeout waits 1000ms, runs the function and then sets another timeout. So the wait period is actually a bit more than 1000ms (or a lot more if your function takes a long time to execute).

Altough one might think that setInterval will execute exactly every 1000ms, it is important to note that setInterval will also delay, since JavaScript isn't a multi-threaded language, which means that - if there are other parts of the script running - the interval will have to wait for that to finish.

In this Fiddle, you can clearly see that the timeout will fall behind, while the interval is almost all the time at almost 1 call/second (which the script is trying to do). If you change the speed variable at the top to something small like 20 (meaning it will try to run 50 times per second), the interval will never quite reach an average of 50 iterations per second.

The delay is almost always negligible, but if you're programming something really precise, you should go for a self-adjusting timer (which essentially is a timeout-based timer that constantly adjusts itself for the delay it's created)

查看更多
看淡一切
6楼-- · 2018-12-31 00:49

To look at it a bit differently: setInterval insures that a code is run at every given interval (i.e. 1000ms, or how much you specify) while setTimeout sets the time that it 'waits until' it runs the code. And since it takes extra milliseconds to run the code, it adds up to 1000ms and thus, setTimeout runs again at inexact times (over 1000ms).

For example, timers/countdowns are not done with setTimeout, they are done with setInterval, to ensure it does not delay and the code runs at the exact given interval.

查看更多
栀子花@的思念
7楼-- · 2018-12-31 00:50

I've made simple test of setInterval(func, milisec), because I was curious what happens when function time consumption is greater than interval duration.

setInterval will generally schedule next iteration just after the start of the previous iteration, unless the function is still ongoing. If so, setInterval will wait, till the function ends. As soon as it happens, the function is immediately fired again - there is no waiting for next iteration according to schedule (as it would be under conditions without time exceeded function). There is also no situation with parallel iterations running.

I've tested this on Chrome v23. I hope it is deterministic implementation across all modern browsers.

window.setInterval(function(start) {
    console.log('fired: ' + (new Date().getTime() - start));
    wait();
  }, 1000, new Date().getTime());

Console output:

fired: 1000    + ~2500 ajax call -.
fired: 3522    <------------------'
fired: 6032
fired: 8540
fired: 11048

The wait function is just a thread blocking helper - synchronous ajax call which takes exactly 2500 milliseconds of processing at the server side:

function wait() {
    $.ajax({
        url: "...",
        async: false
    });
}
查看更多
登录 后发表回答