簡體   English   中英

Javascript setTimeout無法在for循環中工作

[英]Javascript setTimeout not working in a for-loop

我必須每秒更改圖像的來源。 我有一個for循環,其中調用一個具有超時的函數。 我在這里讀取了stackOverflow,但它不起作用。 可以請有人告訴我,我可以修復什么使其工作? 我一直在努力解決這個問題,我想承認。 謝謝。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <script type="text/javascript">
        function changeImage(k) {
            setTimeout(function(){
              document.getElementById("img").src = k + ".png"; alert(k  );}, 1000);
        }
        function test() {
            for (var k = 1; k <= 3; k++) {
                changeImage(k);

            }
        }
    </script>
</head>

<body>
    <div id="main_img">
        <img id="img" src="http://placehold.it/110x110">
    </div>
    <input type="button" style="width: 200px" onclick="test()" />
</body>

在您的代碼中,您可以立即設置所有超時。 所以,如果你將它們都是一個二現在他們火一家其次從現在。

您已經在索引k傳遞,因此只需將時間參數乘以k

setTimeout(function(){
  document.getElementById("img").src = k + ".png";
  alert(k);
}, k * 1000);
// ^ added

問題是您正在創建一個相隔毫秒的計時器實例。 一秒鍾后,它們也會分開幾毫秒。 你需要的是以彼此相隔的設定間隔執行它們。

您可以使用setInterval使用計時器,該計時器以給定的間隔執行提供的函數。 不要忘記殺掉計時器,否則它會永遠運行。

次要優化

  • 您可以將元素緩存在變量中,這樣您就不會經常訪問DOM。

  • 另外,我會避開alert() 如果要調試,請在調試器中使用斷點。 如果你真的希望它是“類似警報”,那么使用console.log並觀察控制台。

  • setInterval優於遞歸setTimeout一個優點是,您不會在每次迭代時生成多個計時器,而只會生成一個計時器。

這是建議的解決方案:

var k = 0; 
var image = document.getElementById("img");
var interval = setInterval(function() {

   // Increment or clear when finished. Otherwise, you'll leave the timer running.
   if(k++ < 3) clearInterval(interval);
   image.src = k + ".png";

// Execute block every 1000ms (1 second)
},1000);

而不是使用循環,你可以這樣做:

var k = 0; 
var int = setInterval(function() {
   if (k <= 3) k++;
   else { clearInterval(int); }
   document.getElementById("img").src = k + ".png"; 
   alert(k);
}, 1000);

問題

setTimeout不會停止程序執行,只會在1秒內為回調設置一個事件。 這意味着如果你在for循環中設置了三個setTimeout,它們將在1秒后同時執行。

一個解法

您可以使用延遲遞歸,而不是使用for循環。

function changeImage(imageIndex) {
    document.getElementById("img").src = imageIndex + ".png"; 
    alert(imageIndex);
}

function myLoop( imageIndex ) {
    if( imageIndex >= 3 ) return;

    changeImage( imageIndex );

    setTimeut( function() { myLoop(imageIndex + 1) }, 1000 );
}

setTimeut( function() { myLoop(0) }, 1000 );

另一種使用setInterval的解決方案

var interval = null;
var imageIndex = 0;

function changeImage() {
    document.getElementById("img").src = imageIndex + ".png"; 
    alert(imageIndex);

   imageIndex++;
   if( imageIndex === 3 ) clearInterval( interval );
}

interval = setInterval( changeImage , 1000);

使用不同的延遲

function changeImage(imageIndex) {
    document.getElementById("img").src = imageIndex + ".png"; 
    alert(imageIndex);
}

for( var i=0; i < 3; i++) {
    setTimeout( changeImage.bind(window, i), i * 1000 );
}

一個groovy一個襯墊(請不要使用它,永遠!)

(function f(i) { setTimeout( changeImage(i) || f.bind(window, i = (i++)%3), 1000); })(0)

我的建議是使用console.log()或alert()來幫助你調試 - 這將使得它變得更加明顯正在發生的事情。 例如,如果你在test或setTimeout函數中放置了console.log,你會發現所有三個圖像都是同時添加的。

我建議的是聲明你的“nextImage”函數,然后在該函數中定義你的setTimeout。 這樣它每秒都會自稱。

另一個提示:我假設您希望這三個圖像永遠循環,所以我添加了一個常用的技巧與模數運算符(%)來完成此任務。

看一看:

工作演示: http//jsfiddle.net/franksvalli/PL63J/2/

(function(){
    var numImages = 3,  // total count of images
        curImage  = 1,  // start with image 1
        $image    = document.getElementById("img"),
        imageBase = "http://placehold.it/110x11";

    function nextImage() {
        $image.src = imageBase + curImage;

        // increment by one, but loop back to 1 if the count exceeds numImages
        curImage = (curImage % numImages) + 1;

        // execute nextImage again in roughly 1 second
        window.setTimeout(nextImage, 1000);
    }

    // initializer.  Hook this into a click event if you need to
    nextImage();
})();

正如其他人所說,你可能想要使用setInterval,你可以通過一些調整來做:

(function(){
    var numImages = 3,  // total count of images
        curImage  = 1,  // start with image 1
        $image    = document.getElementById("img"),
        imageBase = "http://placehold.it/110x11";

    function nextImage() {
        $image.src = imageBase + curImage;

        // increment by one, but loop back to 1 if the count exceeds numImages
        curImage = (curImage % numImages) + 1;
    }

    // initializer.  Hook this into a click event if you need to
    nextImage(); // call function immediately without delay
    window.setInterval(nextImage, 1000);
})();

為什么它不起作用?

因為Javascript總是通過引用傳遞變量。 當您的代碼在隊列中等待時,變量已經更改。

我的解決方案

創建一個數組並按照出現的順序推送您想要執行的任何代碼(直接放置變量的實際值),例如:

var launcher = [];
launcher.push('alert("First line of code with variable '+ x +'")');
launcher.push('alert("Second line of code with variable '+ y +'")');
launcher.push('alert("Third line of code with variable '+ z +'")');

使用setInterval而不是setTimeout來執行代碼(您甚至可以動態更改延遲時間),例如

var loop = launcher.length;
var i = 0;
var i1 = setInterval(function(){
    eval(launcher[count]);
    count++;
    if(i >= loop) {
        clearInterval(i1);
    }
}, 20);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM