setTimeoutの問題
-
26-09-2019 - |
質問
最近、同じ関数について質問したところ、while ループを使用していたため問題が解決され、チュートリアルに誘導されました。つまり、関数はアニメーション化されず、フリーズしてサイズ変更されるだけでした。setTimeout を使用するこの新しい方法は機能するはずです。唯一のことは、アニメーション化するのではなく、新しいサイズにスナップするだけであるということです。Firebugによるとエラーはありません。これがアニメーションを管理するコードの現在のセクションです。
// Resize in timeframe
// Work out distance
var widthdiff = width - parseInt(element.style.width);
var heightdiff = height - parseInt(element.style.height);
// Work out how miliseconds per step (100 in total)
var steptime = timeframe / 100;
// Work out how many pixels it needs to move each step
var widthpps = widthdiff / 100; // ERROR?
var heightpps = heightdiff / 100;
// Set up original sizes
var origwidth = parseInt(element.style.width);
var origheight = parseInt(element.style.height);
// Loop through all 100 steps setting a time out resize each time
var timers = [];
for(var i = 0; i < 100; i++)
{
timers[i] = setTimeout(function() { // ERROR?
element.style.width = origwidth + (widthpps * i) + 'px';
element.style.height = origheight + (heightpps * i) + 'px';
}, i * steptime);
}
引数は問題なく渡されています。すべてをテストし、一度アニメーション化しましたが、ただ間違っていました。したがって、私の問題は「ERROR?」というコメントに近いものになります。私は信じます。助けていただきありがとうございます。
解決
問題は、変数「i」が次のようになることです。 共有 すべてのタイムアウト機能によって。
書くことができます 別 関数を使用してタイムアウト関数を構築することも、関数をインラインでラップすることもできます。
timers[i] = setTimeout((function(privateEye) {
return function() {
element.style.width = origwidth + (widthpps * privateEye) + 'px';
element.style.height = origheight + (heightpps * privateEye) + 'px';
})(i), i * steptime);
「i」が「共有」されると言うとき、私が言いたいのは、ループ内で構築する各関数がそのループ変数を正しく参照するということです。しかし、その変数に何が起こっているのでしょうか?ループを繰り返すたびに変化します。関数が参照することを理解することが重要です。 本物 「i」変数。凍結されたコピーではありません。を使用することで、 2番 関数、上で行ったように、 コピー ループ内で使用される「i」の値。
他のヒント
コードを完全には監査していませんが、ここに症状と一致するエラーがあります。
timers[i] = setTimeout(function() { // ERROR?
element.style.width = origwidth + (widthpps * i) + 'px'; // <== error
element.style.height = origheight + (heightpps * i) + 'px'; // <== error
}, i * steptime);
問題は、関数が ライブリファレンス に i
, 、ループの反復時点での値のコピーではありません。それで彼らは皆見ます i
最後の値の時点で。
これは簡単に修正できます。
timers[i] = setTimeout(makeStepFunction(i), i * steptime);
// Anywhere in the surrounding function, not in the loop:
function makeStepFunction(step) {
return function() {
element.style.width = origwidth + (widthpps * step) + 'px';
element.style.height = origheight + (heightpps * step) + 'px';
};
}
さて、この関数は、 setTimeout
will call は、に渡された引数を使用します。 makeStepFunction
, 、 それよりも i
.
あなた できる 名前付き関数を使用せずにこれを実行しますが、すぐに混乱してしまいます。
timers[i] = setTimeout((function(step) {
return function() {
element.style.width = origwidth + (widthpps * step) + 'px';
element.style.height = origheight + (heightpps * step) + 'px';
};
})(i), i * steptime);
これはすべて、クロージャ (データを「閉じる」関数) が JavaScript でどのように動作するかに関係しています。これらは非常に強力ですが、その仕組みを理解すれば、それほど複雑ではありません。FWIW、私のブログ投稿 クロージャは複雑ではありません 役立つかもしれません。それらがどのように機能するかを理解すると、その謎は失われます(そしてさらに便利になります)。
別の解決策は、setInterval を使用し、パスごとに更新されるグローバル i と setInterval i がキャンセルされたカットオフ値をメソッドで使用することです。
var i = 0;
var interval = setInterval(
function() {
element.style.width = origwidth + (widthpps * i) + 'px';
element.style.height = origheight + (heightpps * i) + 'px';
i++;
if(i==100)
clearInterval(interval); //Stops executing
}, stepTime);
setTimeout と setInterval がどのように機能するかについての説明を見つけて、どちらが目的に最適かを確認してください。http://ejohn.org/blog/how-javascript-timers-work/