Chrome:タイムアウト/間隔がバックグラウンドタブで中断されましたか?


130

私はこのテストsetTimeout使用して精度をテストしていました。今、私は(予想どおり)setTimeoutあまり正確ではないことに気付きましたが、ほとんどのアプライアンスでは劇的に不正確ではありません。Chromeでテストを実行し、バックグラウンドタブで実行した場合(つまり、別のタブに切り替えてそこを参照)、テストに戻り、結果を検査する(テストが終了した場合)と、劇的に変化します。タイムアウトの実行が大幅に遅くなっているようです。FF4またはIE9でテストされたが、これは発生しなかった。

したがって、Chromeはフォーカスのないタブでjavascriptの実行を一時停止または少なくとも遅くするように見えます。件名のネットで多くを見つけることができませんでした。これは、たとえばXHR呼び出しを使用してサーバーで定期的にチェックするなど、バックグラウンドタスクを実行できないことを意味しますsetInterval(私がと同じ動作をするのsetIntervalではないかと思われます。時間があれば、テストを作成します)。

誰かがこれに遭遇しましたか?この一時停止/速度低下の回避策はありますか?それをバグと呼びますか?そのように報告しますか?


面白い!タブに再度アクセスしたときに、Chromeが一時停止してタイマーを再開しているか、タイマーを再起動しているかを確認できますか?または、動作はランダムですか?Chromeがタブを独立したプロセスで実行しているという事実と何か関係があるのでしょうか?
HyderA、

@gAMBOOKa:@ pimvdbの答えを見てください。おそらく、1秒あたり最大1回の速度低下です。
KooiInc

4年後、この問題はまだ存在しています。私はdivのsetTimeOutを持っているtransitionので、すべてのdiv が同時に遷移するわけではありませんが、実際には互いの15ms後に遷移し、ローリングエフェクトを作成します。別のタブに移動してしばらくすると、すべてのdivが同時に遷移し、setTimeOutは完全に無視されます。それは私のプロジェクトにとって大きな問題ではありませんが、奇妙で不要な追加です。
Rvervuur​​t 2015

シーケンスでsetTimeoutを呼び出すアニメーションの場合、解決策は、タイマーのハンドル/ ID(setTimeoutから返される)を覚えていることを確認することです。新しいタイマーを設定する前に、最初にclearTimeoutを呼び出します。ハンドルを手に入れました。私たちの場合、これは、タブに戻ったときに、どのアニメーションが再生されているかという点で最初の奇妙さがあるかもしれませんが、それはすぐに解決され、通常のアニメーションが再開します。私たちはこれが最初はコードの問題だと思っていました。
アクションダン

回答:


88

私は最近これについて尋ねました、そしてそれは仕様による行動です。タブが非アクティブの場合、最大で1秒に1回だけ関数が呼び出されます。これがコードの変更です。

おそらくこれは役立つでしょう: Chromeでタブが非アクティブなときにsetIntervalを機能させるにはどうすればよいですか?

TL; DR:Webワーカーを使用します


3
おかげで、私は「非アクティブなタブ」で見ていたはずです。英語を母国語としないことは、時にはハンディキャップです。
KooiInc、

1
@Kooilnc:問題ありません:)私も英語のネイティブスピーカーではありません。
pimvdb

22

Webワーカーは別のプロセスで実行され、速度が低下しないため、Webワーカーを使用するソリューションがあります。

私はコードを変更せずに使用できる小さなスクリプトを作成しました-それは単に関数setTimeout、clearTimeout、setInterval、clearIntervalをオーバーライドします

すべてのコードの前に含めるだけです

http://github.com/turuslan/HackTimer


7
1.ワーカーはDOMにアクセスできない、2。ワーカーは自分自身でファイルを操作している場合にのみ実行される それはだないドロップインのsetTimeoutの代替例ロットの。
マダラのゴースト

1
あなたは正しいですが、一部の最新のブラウザでは、Blobshtml5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers)を使用することにより、独自のファイルなしでワーカーを使用できます
Ruslan Tushov

1
それでも、WebワーカーにはsetTimeoutやcoの安全な代替となることができる多くの機能(つまり、DOM)がありません。
マダラのゴースト

フロントエンドで実行する必要があるコード、たとえば、他の処理を実行しながら終了したい重いグラフィックス処理タスクについてはどうでしょうか。
Michael

ワーカー、サービスワーカーを作成し、データURLを使用してキャンバスAPIを使用できます。new Worker('data:text/javascript,(' + function myWorkerCode () { /*...*/ } + '()')。インポート式がサポートされているかどうかを確認するのにもよい方法です。try { eval('import("data:text/javascript,void 0")') } catch (e) { /* no support! */ }
FábioSantos

9

空のサウンドを再生すると、ブラウザはパフォーマンスを維持します-このコメントを読んだ後、それを発見しました:ChromeでJavaScriptをChromeで通常の速度で実行するには、タブがアクティブではありませんか?

WebSocketを使用するブラウザーゲームのオンデマンドの無制限のパフォーマンスが必要なので、経験から、WebSocketを使用しても無制限のパフォーマンスは保証されませんが、テストから、オーディオファイルを再生すると保証されるようです

この目的のために作成した2つの空のオーディオループを次に示します。商業的に自由に使用できます。http//adventure.land/sounds/loops/empty_loop_for_js_performance.ogg http://adventure.land/sounds/loops/empty_loop_for_js_performance.wav

(それらには-58dbノイズが含まれ、-60dbは機能しません)

私は、Howler.jsを使用して、ユーザーの要求に応じてそれらを再生します:https : //github.com/goldfire/howler.js

function performance_trick()
{
    if(sounds.empty) return sounds.empty.play();
    sounds.empty = new Howl({
        src: ['/sounds/loops/empty_loop_for_js_performance.ogg','/sounds/loops/empty_loop_for_js_performance.wav'],
        volume:0.5,
        autoplay: true, loop: true,
    });
}

デフォルトでは完全なJavaScriptのパフォーマンスをオン/オフにする組み込みの方法がないのは残念ですが、クリプトマイナーはプロンプトなしでWebワーカーを使用してすべてのコンピューティングスレッドをハイジャックできます:|


ありがとう、58dbはヘッドフォンでも非常に聞こえますが、サイトをミュートすると問題が解決します
Kaan Soral

1

Chrome、Firefox、IEの非アクティブなタブでWeb-Workersを使用して実行し続けるsetIntervalおよびclearIntervalの実装であるworker-interval npmパッケージをリリースしました。

最近のブラウザーのほとんど(Chrome、Firefox、IE)、間隔(ウィンドウタイマー)は、非アクティブなタブで1秒に1回以下の頻度で起動するようにクランプされています。

詳細については、

https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval

https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Timeouts_and_intervals


0

jQueryコアを1.9.1に更新し、非アクティブなタブの間隔の不一致を解決しました。最初にそれを試してから、他のコードオーバーライドオプションを調べます。


どのバージョンからアップグレードしましたか?バージョン
〜1.6で

0

これが現在のミリ秒を取得し、それが関数が作成されたミリ秒と比較する私のソリューションです。間隔については、関数を実行するときにミリ秒を更新します。間隔/タイムアウトをIDで取得することもできます。

<script>

var nowMillisTimeout = [];
var timeout = [];
var nowMillisInterval = [];
var interval = [];

function getCurrentMillis(){
    var d = new Date();
    var now = d.getHours()+""+d.getMinutes()+""+d.getSeconds()+""+d.getMilliseconds();
    return now;
}

function setAccurateTimeout(callbackfunction, millis, id=0){
    nowMillisTimeout[id] = getCurrentMillis();
    timeout[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisTimeout[id] + +millis)){callbackfunction.call(); clearInterval(timeout[id]);} }, 10);
}

function setAccurateInterval(callbackfunction, millis, id=0){
    nowMillisInterval[id] = getCurrentMillis();
    interval[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisInterval[id] + +millis)){callbackfunction.call(); nowMillisInterval[id] = getCurrentMillis();} }, 10);
}

//usage
setAccurateTimeout(function(){ console.log('test timeout'); }, 1000, 1);

setAccurateInterval(function(){ console.log('test interval'); }, 1000, 1);

</script>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.