Javascript setTimeout/setInterval

2019-05-31 06:48发布

问题:

Trying to make a little slideshow for a test webpage. I'm confused as to why this code isn't working (I'm not very experienced with javascript, I mostly deal in Java, Javascript is rather mind blowingly frustrating). Also I'd like to add it does begin to run it'll switch to the 3rd picture after a few seconds then it stops never again switching.

var backgroundElement = document.getElementById("innerContent");
var minibarImage1 = document.getElementById("pic1");
var minibarImage2 = document.getElementById("pic2");
var minibarImage3 = document.getElementById("pic3");


minibarImage1.onmouseover = function(){
    backgroundElement.style.backgroundImage="url('images/frontpage/maintenance_01.jpg')";
};

minibarImage2.onmouseover = function() {
    backgroundElement.style.backgroundImage ="url('images/frontpage/natural_steps_01.jpg')";
};

minibarImage3.onmouseover = function() {
    backgroundElement.style.backgroundImage = "url('images/frontpage/twnshp_bdg_01b.jpg')";
};

function slideshow() {
setTimeout(function(){backgroundElement.style.backgroundImage= "url('images/frontpage/maintenance_01.jpg')";}, 2000);
setTimeout(function(){backgroundElement.style.backgroundImage = "url('images/frontpage/natural_steps_01.jpg')";}, 2000);
setTimeout(function(){backgroundElement.style.backgroundImage = "url('images/frontpage/twnshp_bdg_01b.jpg')";}, 2000);
}   


 window.onload = setInterval(function(){slideshow();}, 8000);

回答1:

As I've already pointed out:

window.onload = setInterval(function(){slideshow();}, 8000);

Should be like this:

window.onload = function(){
    setInterval(function(){slideshow();}, 8000);
}

window.onload stores a function. setInterval returns an id for the interval - so that you can choose to stop it.

Also, setTimeout doesn't pause the execution of the program. So, your consecutive calls to setTimeout all execute at the same time - two seconds after the call to slideshow.

You can try nesting the callback functions, like this:

function slideshow (){

    setTimeout(function(){
        backgroundElement.style.backgroundImage= "url('images/frontpage/maintenance_01.jpg')";
        setTimeout(function(){
            backgroundElement.style.backgroundImage = "url('images/frontpage/natural_steps_01.jpg')";
            setTimeout(function(){
                backgroundElement.style.backgroundImage = "url('images/frontpage/twnshp_bdg_01b.jpg')";
                slideshow();
            },  2000);
        },  2000);
    },  2000);
}

slideshow();

There's probably a more elegant way, but you get the point.

Edit:

This may be more graceful:

function slideshow() {
    setTimeout (function(){backgroundElement.style.backgroundImage = "uri";}, 2000);
    setTimeout (function(){backgroundElement.style.backgroundImage = "uri";}, 4000);
    setTimeout (function(){backgroundElement.style.backgroundImage = "uri";}, 6000);
    setTimeout (slideshow, 8000);
}   

Displacing the seconds by 2. You can even make your slideshow function a little more modular by adding an array of url's and time-step arguments so that you can iterate setTimeout functions over a set of urls.

Sort of like this (pseudo code)

function slideshow (urls, timestep){
    var i = 0;
    for (; urls[i]; i++)
        setTimeout (function(){ backgro... = urls[i];}, timestep * i);

    setTimeout (slideshow, timestep * i);
}

slideshow (["url1", "url2", "url3"], 2000);


回答2:

Regarding your only seeing the third slide show up:

The calls to setTimeout return immediately after simply scheduling other code to run.

So in your slideshow function, you

  1. schedule the first slide to show up in 2 seconds
  2. then immediately schedule the second slide to show up in 2 seconds
  3. then immediately schedule the third slide to show up in 2 seconds

The second slide shows up nanoseconds after the first, then the third just nanoseconds after the second. You can only perceive the third slide showing up!

EDIT

Here's a general approach you can use for a slideshow. (Note there are several libraries out there that can do this for you, but this is actually a very nice exercise for learning JavaScript.)

First, structure your slide show to cycle through images using a counter. In professional JavaScript, you wrap the counter in a closure so as not to pollute the global namespace:

var slideshow = (function () {
    var images = [
        'images/frontpage/maintenance_01.jpg',
        'images/frontpage/natural_steps_01.jpg',
        'images/frontpage/twnshp_bdg_01b.jpg'
    ];
    var index = 0;
    return function () {
        backgroundElement.style.backgroundImage= "url(" + images[index] + ")";
        index = (index + 1) % images.length;
        setTimeout(slideshow, 2000);
    }
}());

Now, you needn't even wait the 8 seconds to start everything up. You can get away with this:

window.onload = slideshow;

Note there are no parens here, because you do not want to assign the result of calling slideshow to onload, you want the onload function to be slideshow.