このアイテムは、私が取り組んでいるアプリケーションの大きな頭痛の種を解決するのに役立ちました。投稿してくれてありがとう。AdjustTickCount ユーティリティは、ソリューションを証明するための優れた不可欠なツールです。
この問題は IE 7 にも影響し、IE 6 にも影響しているように見えますが、ブラウザが一斉に応答を停止し、解決策がそのバージョンでも機能しないように見えるため、さらに悪い結果になります。特にビジネス/エンタープライズの世界では、これらの古いバージョンの多くのユーザーがまだいます。
左マウス ボタンが Windows XP の要因であることがわかりませんでした。それがなくても問題が発生します。
タイムアウトの遅延がせいぜい数秒で、アプリケーションに設定されているタイムアウトの数が非常に少ない場合は、最初の 2 つの回答で問題ありません。より長いタイムアウトが必要な場合は、Web アプリが使用できなくなるのを防ぐために、さらに多くの作業を行う必要があります。qooxdooなどのフレームワークを使用する Web 2.0 RIA では、ユーザーはフレームワークを何日も実行したままにすることができるため、アニメーションやその他の短い効果を生成するために、0.5 秒の数秒の遅延よりも多くの長いタイムアウトが必要になる場合があります。
最初の解決策は良いスタートですが、次のタイムアウトを に設定するtarget-now
と、再び関数がすぐに呼び出されます。これは、稼働時間 + 遅延が 2^32 ミリ秒を超えるため、稼働時間が 0 に戻るまで JS コードがスピンするためです (またはユーザーがブラウザーを強制終了します)。
2 番目の解決策は改善です。なぜなら、早すぎるタイムアウトは 1 秒間隔でのみ発生するためです。これまでは、アップタイム ラップ アラウンドの 1 秒以内であり、他のコードがルックインを取得できるようになっていますが、実験では、ブラウザを作成するのに十分であることが示されています。保留中のタイムアウトが十分にある場合は使用できません。そして、アップタイムがラップアラウンドするまで引き続き続行されるため、要求された遅延が十分に長い場合、ユーザーはブラウザーを強制終了することを決定する可能性があります。
CPU をあまり消費しない解決策は、後続の各タイムアウトの遅延を前の遅延の半分の時間に設定することです。その遅延が 500 ミリ秒未満になるまで、アップタイムのラップアラウンド ポイントが差し迫っていることがわかります (< 1 秒先)。また、次のタイムアウトを に設定してtarget-now
、さらに少数のサイクルの後に早すぎるタイムアウトのチェックを停止することができます。これに到達するまでにかかる時間は、元の遅延の長さと、呼び出されたときのアップタイム ラップ アラウンドにどれだけ近づいたかによって異なりますsetSafeTimeout
が、最終的には最小限の CPU 負荷で、ユーザーが長時間のスローダウンを経験することなく、アプリケーションは通常の動作に戻ります。
このようなもの:
function setSafeTimeout(func, delay) {
var target = +new Date + delay;
var newDelay = delay;
var helper = function()
{
var now = +new Date;
if (now < target)
{
newDelay /= 2; // halve the wait time and try again
if(newDelay < 500) // uptime wrap around is imminent
{
newDelay = target-now; // go back to using original target
}
var handle = setTimeout(helper, newDelay);
// if required record handle somewhere for clearTimeout
}
else
{
func();
}
};
return setTimeout(helper, delay);
};
さらなる改良:
setTimeout()
システムのアップタイム ティックが 2^32ms に近くない場合でも、予想よりも数ミリ秒早くコールバックを呼び出すことがあることがわかりました。この場合、上記の関数で使用される次の待機間隔は、元のターゲットまでの残り時間よりも長くなる可能性があり、その結果、当初の予定よりも長く待機することになります。
以下は、この問題を解決する別のバージョンです。
function setSafeTimeout(func, delay) {
var target = +new Date + delay;
var newDelay = delay;
var helper = function()
{
var now = +new Date;
if (now < target)
{
var timeToTarget = target-now;
newDelay /= 2; // halve the wait time and try again
if(newDelay < 500 || newDelay > timeToTarget) // uptime wrap around is imminent
{
newDelay = timeToTarget; // go back to using original target
}
var handle = setTimeout(helper, newDelay);
// if required record handle somewhere for clearTimeout
}
else
{
func();
}
};
return setTimeout(helper, delay);
};