setTimeout delay not working

2019-01-18 10:08发布

问题:

I trying to wrap my head around setTimeout, but I can't get it to work properly.

I have set up an example here: http://jsfiddle.net/timkl/Fca2n/

I want a text to countdown after an anchor is clicked - but my setTimeout seems to fire on the same time, even though I've set the delay to 1 sec.

This is my HTML:

<a href="#">Click me!</a>

<span id="target"></span>

This is my JS:

$(document).ready(function() {


function foo(){

    writeNumber = $("#target");

    setTimeout(writeNumber.html("1"),1000);
    setTimeout(writeNumber.html("2"),1000);
    setTimeout(writeNumber.html("3"),1000);
    };

$('a').click(function() {
 foo();
});

});

Any hint on what I could be doing wrong is highly appreciated :)

回答1:

setTimeout takes a function as an argument. You're executing the function and passing the result into setTimeout (so the function is executed straight away). You can use anonymous functions, for example:

setTimeout(function() {
    writeNumber.html("1");
}, 1000);

Note that the same is true of setInterval.



回答2:

You need to wrap your statements in anonymous functions and also stagger your timings -

setTimeout(function(){writeNumber.html("1")},1000);
setTimeout(function(){writeNumber.html("2")},2000);
setTimeout(function(){writeNumber.html("3")},3000);

If you set everything to 1000 the steps will pretty much run simultaneously as the setTimeout function will run the task 1 second after you called the function not 1 second after the previous call to the setTimeout function finished.

Demo - http://jsfiddle.net/JSe3H/1/



回答3:

You need to use a function reference to be invoked later when the timer expires. Wrap each statement in an anonymous function so that it isn't executed immediately, but rather when the timer expires.

setTimeout(function() { writeNumber.html("1"); },1000);

Also, you want to use a different delay value for each one so that the timers don't expire at the same time. See an updated fiddle at http://jsfiddle.net/RqCqM/



回答4:

There is a provision to pass arguments to the function. In your case, you can do it by

setTimeout(writeNumber.html,1000,1);
setTimeout(writeNumber.html,1000,2);
setTimeout(writeNumber.html,1000,3);

third argument to setTimeout function will be pass to writeNumber.html function



回答5:

Just use setInterval(). Here's what I came up with. Here's your new javascript:

function foo(){
    writeNumber = $("#target");
    number      = 0;
    writeNumber.html(number);
    setInterval(function(){
        number = number+1;
        writeNumber.html(number);
    },1000);
    };
$('a').click(function() {
 foo();
});


回答6:

You need tot use a functions to be called after the timeout is passed; you can use anonymous function too, then your function foo will look like this:

function foo(){

writeNumber = $("#target");

setTimeout(function() { writeNumber.html("1"); },1000);
setTimeout(function() { writeNumber.html("2"); },1000);
setTimeout(function() { writeNumber.html("3"); },1000);

};


回答7:

I landed on this question. It has been answered adequately, and I think using setInterval as @Purag suggested is probably the best approach to get the desired functional behaviour. However the initial code example did not take JavaScript's asynchroneous behaviour into account. This is an often occurring error, which I've made myself on more than occasion :).

So as a side note I wanted to give another possible solution for this which mimics the initial attempt, but this time DOES consider Javascript's Asynchronousity:

setTimeout(function() {
    writeNumber.html("1");
    setTimeout(function() {
        writeNumber.html("1");
        setTimeout(function() {
            writeNumber.html("1");
        }, 1000);
    }, 1000);
}, 1000);

Now ofcourse this is clearly terrible code!

I have given a working JSFiddle of it in my own SO question. This code exemplifies the so-called pyramid of doom. And this can be mitigated by using JavaScript promises, as shown in the answers to my question. It takes some work to write a version of WriteNumber() that uses Promises, but then the code can be rewritten to somehting like:

writeNumAsync(0)
    .then(writeNumAsync)
    .then(writeNumAsync)
    .then(writeNumAsync);