3

アニメーションの目的で各繰り返しを遅らせる必要があるforループがあります。setTimeOut関数を削除すると、次のコードが適切に循環し、変数がループ内で正しくインクリメントされ、その後、最終行が実行されます。しかし、setTimeoout関数を使用すると、一番下の行が最初に実行され、次にforループが7回実行され(6回である必要があります)、毎回x=6であることがわかります。明らかに私は何か間違ったことをしています。何か案は?

for ( x = 0; x <= 5; x++) {
    setTimeout(function() {
        alert("For loop iteration #" + x);
    }, 500 * x);
}
alert("Code to be executed after completed for loop");
4

3 に答える 3

5

xクロージャコンテキストで現在の値を保存するには、クロージャが必要です。

 for (var x = 0; x <= 5; x++) {
    (function(x) {
        setTimeout(function(){
            alert("For loop iteration #" + x);
            if (x == 5) {
                setTimeout(function(){
                    alert("Code to be executed after completed for loop");
                });
            }
        }, 5 * x);

    })(x);
}
于 2013-03-10T21:21:01.587 に答える
3

これはよくある概念上の間違いです。

  1. Javascriptはノンブロッキングです
  2. 実際の値ではなく、変数への参照が渡されます

x変数は動的であることに注意する必要があります。への参照は、値xではなくに渡されalert("For loop iteration #" + x);ます。したがって、alertfinallyが実行されると、が開始さxれた時点ではなく、実行時点での値になります。setTimeout

基本的には次のようになります。
ループが処理され、6つのタイムアウトが作成され、その直後にが表示されますalert("Code to be executed after completed for loop");。その後、しばらくするとタイムアウトが実行され、ループが終了した後の状態で変数xがすべて表示されます- 6

変数自体xへの参照ではなく、の値がアラートに渡されるように、クロージャが必要です。x

for (var x = 0; x <= 5; x++) {
    (function(z) {
        setTimeout(function() {
            alert("For loop iteration #" + z);
        }, 5 * z);
    })(x);
}

編集:

2番目の問題に取り組むには、コールバック関数を使用する必要があります。CB関数はコードの論理的な継続ですが、すぐには実行されませんが、特定のポイント(最後のアラートが発生した)まで停止する必要があります。次のように実装します。

for (var x = 0; x <= 5; x++) {
    (function(z) {
        setTimeout(function() {
            alert("For loop iteration #" + z);
            if (z===5){ continue_code() }
        }, 5 * z);
    })(x);
}

function continue_code(){
    alert("Code to be executed after completed for loop");
    // Here comes all your code
    // which has to wait for the timeouts from your for loop
}

最後のsetTimeoutで、コードの実行を継続する関数を呼び出します。

于 2013-03-10T21:21:27.640 に答える
1

x はグローバル変数です。最初のアラートが発生するまでに、それを 6 に増やしました。これが発生したくない場合は、代わりに次のようなものを使用してください。これは、500 ミリ秒ごとに呼び出される関数内でインクリメントします。

var x = 0;
var interval = setInterval(function() {
    alert("Loop iteration #" + x++);
    if(x==5) {
        clearInterval(interval);
        alert("Code to be executed after completing loop");
    }
}, 500);
于 2013-03-10T21:19:00.150 に答える