javascript:すべてのタイムアウトをクリアしますか?


99

特定のウィンドウからすべてのタイムアウトをクリアする方法はありますか?タイムアウトはwindowオブジェクトのどこかに格納されていると思いますが、確認できませんでした。

クロスブラウザーソリューションは大歓迎です。



6
おい、この質問は3年前からのものであり、それには素晴らしい答えがあります。それをいじる必要はありません。
marcio 2015

私はこれを検索し、両方を見つけました。あなたの方が年上だったので、2つの質問を1つに減らすのは良いハウスキーピングだと思いました。鉱山は一票です。閉じるには投票する必要がある人がかなり多く、重複したリンクが他の人を助ける可能性があります。
Bernhard Hofmann

2
@Bernard Hofmannこれがより良い答えを得た場合、それが重複した質問としてカウントされるかどうかはわかりません。2010年からのそれに対する受け入れられた答えは「いいえ」でした。
RoboticRenaissance 2017年

回答:


148

それらはウィンドウオブジェクトにはありませんが、IDを持っています。これは連続した整数です(afaik)。

したがって、次のようにすべてのタイムアウトをクリアできます。

var id = window.setTimeout(function() {}, 0);

while (id--) {
    window.clearTimeout(id); // will do nothing if no timeout with id is present
}

1
これは仕様の一部ですか、それとも実装依存ですか?
Tikhon Jelvis 2012年

7
1から始める必要はありません。HTML5仕様では、「ハンドルは、この呼び出しによって設定されるタイムアウトを識別する、ゼロより大きいユーザーエージェント定義の整数にしてください」と述べています。これにより、ハンドルには、連続していない整数や小さい整数を含む任意の正の整数を使用できます。
マイクサミュエル

3
これは非常に賢い方法ですが、OPはおそらく、アクティブなタイマーを追跡するより良いソリューションがあるかどうかを尋ねるはずです。
Jason Harwig、2012年

3
これは無限ループではありませんか?すべてのブラウザがif(0)をfalseとしてレンダリングするわけではありません。
Travis J、

2
すべてのタイムアウトをクリアする方法を尋ねたので、この回答を受け入れます。非常に賢いソリューション。
marcio 2012年

79

これを達成する最も簡単な方法は、すべてのsetTimeout識別子を1つの配列に格納することです。この配列では、すべての識別子を簡単に反復できclearTimeout()ます。

var timeouts = [];
timeouts.push(setTimeout(function(){alert(1);}, 200));
timeouts.push(setTimeout(function(){alert(2);}, 300));
timeouts.push(setTimeout(function(){alert(3);}, 400));

for (var i=0; i<timeouts.length; i++) {
  clearTimeout(timeouts[i]);
}

14
これが唯一クリアのボーナス(または潜在的な欠点、私は推測)は、あなたが設定し、あなたがうっかり外のコードを壊すことはありません。
Tikhon Jelvis 2012年

1
+1、すべてのタイムアウトをクリアするわけではありませんが、特定のタイムアウトのグループを一度にクリアするための優れたソリューションです
marcio

1
これは外部コードを壊さないので最良の解決策ですが、すべてのタイムアウトをクリアする方法を尋ねたので、@ Pumbaa80回答を受け入れてしまいました:)
marcio

2
@marcioAlmada奇妙ですが、2.5年後のこのコメントに再び戻ってくるのを見るのはクールです:)
Michael

6
自分が制御していないWebページにアクセスしたときに、すべてのタイムアウトと間隔をクリアしたいのかもしれません。これは、adblockerが実行されるまで開始しない迷惑なポップアップ広告があるためです。
RoboticRenaissance 2017年

12

私はPumbaa80の回答に加えて、古いIE向けに開発している人に役立つかもしれません。

はい、すべての主要なブラウザーはタイムアウトIDを連続した整数として実装しています(仕様では必須ではありません)。開始番号はブラウザによって異なります。Opera、Safari、Chrome、IE> 8は1からタイムアウトIDを開始し、Geckoベースのブラウザーは2から、IE <= 8はタブの更新時に魔法のように保存された乱数から開始しているようです。自分で発見できる

つまり、IEで8以下のwhile (lastTimeoutId--)サイクルが8 桁以上実行され、「このページのスクリプトが原因でInternet Explorerの実行が遅くなっています」というメッセージが表示される可能性があります。したがって、すべてのタイムアウトIDを保存できない場合、またはwindow.setTimeoutオーバーライドしたくない場合は、ページの最初のタイムアウトIDを保存し、それまでタイムアウトをクリアすることを検討してください。

早期ページ読み込み時にコードを実行します。

var clearAllTimeouts = (function () {
    var noop = function () {},
        firstId = window.setTimeout(noop, 0);
    return function () {
        var lastId = window.setTimeout(noop, 0);
        console.log('Removing', lastId - firstId, 'timeout handlers');
        while (firstId != lastId)
            window.clearTimeout(++firstId);
    };
});

そして、おそらく外部コードによって設定された保留タイムアウトをすべてクリアします


さらに、いくつかのより詳細な情報を明確にするための1つ。
Sanjay

8

タイムアウトIDをグローバル配列に保存し、関数呼び出しをウィンドウに委譲するメソッドを定義してはどうでしょう。

GLOBAL={
    timeouts : [],//global timeout id arrays
    setTimeout : function(code,number){
        this.timeouts.push(setTimeout(code,number));
    },
    clearAllTimeout :function(){
        for (var i=0; i<this.timeouts.length; i++) {
            window.clearTimeout(this.timeouts[i]); // clear all the timeouts
        }
        this.timeouts= [];//empty the id array
    }
};

3

window.setTimeoutメソッドを書き直して、タイムアウトIDを保存する必要があります。

const timeouts = [];
const originalTimeoutFn = window.setTimeout;

window.setTimeout = function(fun, delay) { //this is over-writing the original method
  const t = originalTimeoutFn(fn, delay);
  timeouts.push(t);
}

function clearTimeouts(){
  while(timeouts.length){
    clearTimeout(timeouts.pop();
  }
}

3

すべてのタイムアウトをクリアするには、最初に「キャプチャ」する必要があります。

以下のコードを他のスクリプトの前に配置すると、元のsetTimeout&のラッパー関数が作成されますclearTimeout

新しいclearTimeoutsメソッドがwindowオブジェクトに追加され、すべての(保留中の)タイムアウトをクリアできるようになります(Gistリンク)。

他の回答は、受け取られる可能性のある議論に対する完全なサポートを欠いています。 setTimeout

// isolated layer wrapper (for the local variables)
(function(_W){

var cache = [],                // will store all timeouts IDs
    _set = _W.setTimeout,      // save original reference
    _clear = _W.clearTimeout  // save original reference

// Wrap original setTimeout with a function 
_W.setTimeout = function( CB, duration, arg ){
    // also, wrap the callback, so the cache reference will be removed 
    // when the timeout has reached (fired the callback)
    var id = _set(function(){
        CB.apply(null, arguments)
        removeCacheItem(id)
    }, duration || 0, arg)

    cache.push( id ) // store reference in the cache array

    // id reference must be returned to be able to clear it 
    return id
}

// Wrap original clearTimeout with a function 
_W.clearTimeout = function( id ){
    _clear(id)
    removeCacheItem(id)
}

// Add a custom function named "clearTimeouts" to the "window" object
_W.clearTimeouts = function(){
    console.log("Clearing " + cache.length + " timeouts")
    cache.forEach(n => _clear(n))
    cache.length = []
}

// removes a specific id from the cache array 
function removeCacheItem( id ){
    var idx = cache.indexOf(id)

    if( idx > -1 )
        cache = cache.filter(n => n != id )
}

})(window);

2

完全を期すために、私は一般的な解決策を投稿したいとカバーの両方setTimeoutsetInterval

ブラウザは両方に同じIDのプールを使用しているようですが、いくつかの回答から、Are clearTimeoutとclearIntervalは同じですか?、信頼してclearTimeoutも安全かどうかは明確ではありません。clearInterval同じ機能実行しても、それぞれのタイマータイプでのみ作業。

したがって、目標がすべてのタイムアウトと間隔を強制終了することである場合、すべてのテストを実行できない場合、実装全体でやや防御的になる可能性がある実装を次に示します。

function clearAll(windowObject) {
  var id = Math.max(
    windowObject.setInterval(noop, 1000),
    windowObject.setTimeout(noop, 1000)
  );

  while (id--) {
    windowObject.clearTimeout(id);
    windowObject.clearInterval(id);
  }

  function noop(){}
}

これを使用して、現在のウィンドウのすべてのタイマーをクリアできます。

clearAll(window);

または、それを使用して、すべてのタイマーをクリアできますiframe

clearAll(document.querySelector("iframe").contentWindow);

このアプローチはvue-cli-serviceウォッチャーを破壊するため、すべてのタイムアウトと時間間隔をクリーンアップするときにホットリロードを実行できないことに注意してください。(angular、react、emberなどの)フレームワークの他のホットリロードウォッチャーでも同じだと思います
Michail Michailidis

1

TypescriptでVueを使用しています。

    private setTimeoutN;
    private setTimeoutS = [];

    public myTimeoutStart() {

        this.myTimeoutStop();//stop All my timeouts

        this.setTimeoutN = window.setTimeout( () => {
            console.log('setTimeout');
        }, 2000);

        this.setTimeoutS.push(this.setTimeoutN)//add THIS timeout ID in array

    }

    public myTimeoutStop() {

        if( this.setTimeoutS.length > 0 ) {
            for (let id in this.setTimeoutS) {
                console.log(this.setTimeoutS[id]);
                clearTimeout(this.setTimeoutS[id]);
            }
            this.setTimeoutS = [];//clear IDs array
        }
    }

0

他のすべての関数がタイミングを導き出すグローバルタイムアウトを使用します。これにより、コードが多少抽象化されますが、すべてがより速く実行され、管理が容易になります。


よくわかりません。set_timeoutグローバル関数の動作を拡張するつもりですか?コード例を教えていただけますか?
marcio

1
50msに1回実行される1つのグローバルタイムアウトがあることを意味しました。タイミング要素を必要とする他のすべての関数は、グローバルタイムアウトからそれを取得します。グーグルは効率を上げるためにこれに切り替えたが、それを引用する記事はもう見つからない。
Travis J

0

この正確な問題を解決するパッケージを公開しました。

npm install time-events-manager

これにより、timeoutCollectionintervalCollectionオブジェクトを介してすべてのタイムアウトと間隔を表示できます。removeAllコレクションとブラウザの両方からすべてのタイムアウト/間隔をクリアする関数もあります。

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