3

setInterval によってページ内の他のスクリプトがブロックされる可能性はありますか?

Gmail 関連のブックマークレットを Google Chrome 拡張機能に変換するプロジェクトに取り組んでいます。ブックマークレットは、gmail グリースモンキー API を使用して gmail ページと対話します。API の JavaScript オブジェクトは、Gmail ページで最後に読み込まれる部分の 1 つで、XMLHttpRequest を介してページに読み込まれます。このオブジェクトにアクセスする必要があり、グローバル JavaScript 変数は拡張コンテンツ スクリプトから隠されているため、gmail ページにスクリプトを挿入して、変数の定義をポーリングし、変数の定義にアクセスします。setInterval 関数を使用してポーリングを行っています。これは約 80% の確率で機能します。残りの時間は、設定した制限に達するまでポーリング機能がポーリングを続け、グリースモンキー API オブジェクトがページで定義されることはありません。

挿入されたスクリプトのサンプル:

    var attemptCount = 0;

    var attemptLoad = function(callback) {

        if (typeof(gmonkey) != "undefined"){
            clearInterval(intervalId);  // unregister this function for interval execution.
            gmonkey.load('1.0', function (gmail) {
                self.gmail = gmail;
                if (callback) { callback(); }
            });
        }
        else {
            attemptCount ++;  
            console.log("Gmonkey not yet loaded: " + attemptCount );
            if (attemptCount > 30) {
                console.log("Could not fing Gmonkey in the gmail page after thirty seconds.  Aborting");
                clearInterval(intervalId);  // unregister this function for interval execution.
            };
        }
    };

    var intervalId = setInterval(function(){attemptLoad(callback);}, 1000);
4

2 に答える 2

11

Javascript はシングル スレッドです (ここでは説明していない Web ワーカーを除く)。つまり、実行の通常の JavaScript スレッドが実行されている限り、実行setInterval()の通常の JavaScript スレッドが完了するまで、タイマーは実行されません。

同様に、ハンドラーが実行中の場合、ハンドラーが現在の呼び出しの実行を終了するsetInterval()まで、他の JavaScript イベント ハンドラーは起動しません。setInterval()

setInterval()そのため、ハンドラーが動かなくなって永遠に実行されない限り、他の処理が最終的に実行されるのをブロックすることはありません。少し遅れるかもしれませんが、現在のsetInterval()スレッドが終了するとすぐに実行されます。

内部的には、JavaScript エンジンはキューを使用します。何か (イベント ハンドラーやsetInterval()コールバックなど) を実行する必要があり、何かが既に実行されている場合、キューにイベントが挿入されます。現在の JavaScript スレッドの実行が終了すると、JS エンジンはイベント キューをチェックし、そこに何かがある場合は、そこにある最も古いイベントを選択し、そのイベント ハンドラーを呼び出します。

Javascript イベント システムの仕組みに関するその他のリファレンスを次に示します。

JavaScript はバックグラウンドで AJAX 応答をどのように処理しますか?

Javascript メソッドの呼び出しはスレッドセーフまたは同期化されていますか?

非同期 Javascript の競合状態に注意する必要はありますか?

于 2012-08-15T23:19:40.850 に答える
4

setInterval と setTimeout は「礼儀正しい」ものです。つまり、発生すると思われるときに起動しないという点です。指定した時点の、スレッドがクリアされたときにいつでも起動します。

そのため、何かをスケジュールしても、他の何かの実行が停止されることはありません。現在のキューの最後、または指定された時間 (どちらか長い方) の最後に実行されるように設定されるだけです。

2 つの重要な注意事項:

1 つ目は、setTimeout/setInterval にブラウザー固有の最小値があることです。多くの場合、それらは約 15ms です。したがって、1 ミリ秒ごとに何かを要求すると、ブラウザーは実際にはそれらを browser_min_ms (実際の変数ではない) ごとにスケジュールします。

2 つ目は、setInterval を使用すると、コールバック内のスクリプトが間隔よりも長くかかる場合、ブラウザが間隔のバックログを待ち行列に入れ続ける列車事故に遭遇する可能性があることです。

function doExpensiveOperation () {
    var i = 0, l = 20000000;
    for (; i < l; i++) {
        doDOMStuffTheWrongWay(i);
    }
}


setInterval(doExpensiveOperation, 10);

BadTimes+=1;

しかし、特にあなたのコードについては、あなたがしていることに本質的に問題はありません。私が言ったように、setInterval は他のことを中止せず、次の利用可能なスロットに自分自身を挿入します。

汎用的なものには setTimeout を使用することをお勧めしますが、間隔のタブを保持し、間隔を空けておくという良い仕事をしています。

コードの他の場所 (Google の配信またはコレクション) で何か他のことが起こっている可能性があります。

于 2012-08-15T23:35:38.517 に答える