タイマー使用時の落とし穴

タイマーを使用する過程で、タイマーの詳細を理解していないと、タイマーのいくつかの罠に陥る可能性があります。関数 setTimeout には適時に多くの固有の欠点があるため、時間精度の要件については、次の条件を比較してください。需要が高いため、他のソリューションを的を絞った方法で採用する必要があります

1. 現在のタスクの実行時間が長すぎる場合、期限切れタイマー タスクの実行に影響します。

setTimeout を使用する場合、コールバック関数の実行に設定された期待値よりも時間がかかる要因は数多くありますが、その 1 つは、現在のタスクの実行時間が長すぎるため、タイマーによって設定されたタスクが実行されなくなることです。遅れること。まず次のコードを見てみましょう。

function bar() {
    
    
    console.log('bar')
}
function foo() {
    
    
    setTimeout(bar, 0);
    for (let i = 0; i < 5000; i++) {
    
    
        let i = 5+8+8+8
        console.log(i)
    }
}
foo()

このコードでは、foo 関数の実行時に setTimeout を使用して遅延 0 のコールバック タスクを設定しています。コールバック タスクの設定後、foo 関数は for ループを 5000 回実行し続けます。

setTimeout で設定されたコールバック タスクはメッセージ キューに入れられ、次の実行を待ちます。すぐには実行されません。メッセージ キュー内の次のタスクを実行するには、現在のタスクが実行されるまで待つ必要があります。コードの必要性 for ループは 5000 回実行されるため、現在のタスクの実行時間はさらに長くなります。これは必然的に次のタスクの実行時間に影響します。

2. setTimeout への呼び出しがネストされている場合、システムは最小時間間隔を 4 ミリ秒に設定します。

つまり、タイマー関数内でタイマー呼び出しをネストすると、タイマーの実行時間も延長されます。まず、次のコードを見てください。

function cb() {
    
     setTimeout(cb, 0); }
setTimeout(cb, 0);

上記のコードに問題はありますか?

次の図に示すように、パフォーマンスを通じてこのコードの実行プロセスを記録することができます。

ここに画像の説明を挿入します

上図の縦線はタイマーの関数コールバック処理であり、図からわかるように最初の5回の呼び出しの時間間隔は比較的短く、ネストされた呼び出しは5回を超えています。後続の呼び出しは 4 ミリ秒です。これは、Chrome ではタイマーがネストされて 5 回以上呼び出されると、システムがその関数メソッドがブロックされていると判断し、タイマー呼び出し間隔が 4 ミリ秒未満の場合、ブラウザーがその時間間隔をブロックするためです。通話間隔は 4 ミリ秒に設定されます。

したがって、一部の高度なリアルタイム ニーズには setTimeout を使用することは適していません (たとえば、JavaScript アニメーションを実装するために setTimeout を使用することはあまり良い考えではありません)。

3. 非アクティブなページの場合、setTimeout の最小実行間隔は 1000 ミリ秒です。

前述の 4 ミリ秒の遅延に加えて、見落とされやすい点がもう 1 つあります。それは、非アクティブ ページの最小タイマー値が 1000 ミリ秒を超えていることです。つまり、ラベルが現在のアクティブ ラベルではない場合、次に、最小タイマー値です。時間間隔は 1000 ミリ秒です。これは、バックグラウンド ページの読み込み損失を最適化し、電力消費を削減するためです。タイマーを使用する場合は、この点に注意する必要があります。

4. 遅延実行時間には最大値があります

タイマーのコールバック関数の時間が実際の設定値に比べて遅れることに加えて、もう 1 つ注意する必要がある点があります。つまり、Chrome、Safari、Firefox はすべて 32 ビットを使用して遅延値を保存し、保存できる数値は 2147483647 ミリ秒です。つまり、setTimeout で設定した遅延値が 2147483647 ミリ秒 (約 24.8 日) を超えるとオーバーフローし、すぐにタイマーが実行されます。このコードを実行できます。

function showName(){
    
    
  console.log(" 立即执行了 ")
}
var timerID = setTimeout(showName,2147483648);// 会被理解调用执行

実行後、このコードがすぐに実行されることがわかります。ただし、遅延値が 2147483647 ミリ秒未満の値に変更された場合、実行中に問題は発生しません。

5. setTimeout を使用して設定されたコールバック関数のこれは直感的ではありません

setTimeout によって延期されたコールバック関数がオブジェクトのメソッドである場合、メソッド内の this キーワードは、それが定義されたオブジェクトではなくグローバル環境を指します。この点は以前紹介した際にも触れましたが、以下のコードの実行結果が確認できます。

var name= 1;
var MyObj = {
    
    
  name: 2,
  showName: function(){
    
    
    console.log(this.name);
  }
}
setTimeout(MyObj.showName,1000)

このコードがコンパイルされると、実行コンテキストのこれはグローバル ウィンドウに設定されるため、ここでの出力は 1 になります。厳密モードの場合は、未定義に設定されます。

では、この問題をどうやって解決すればいいのでしょうか?通常は以下の2つの方法が考えられます。

1 つ目は、次に示すように、匿名関数で MyObj.showName を実行することです。

// 箭头函数
setTimeout(() => {
    
    
    MyObj.showName()
}, 1000);
// 或者 function 函数
setTimeout(function() {
    
    
  MyObj.showName();
}, 1000)

2 番目の方法は、bind メソッドを使用して showName を MyObj にバインドする方法です。コードは次のとおりです。

setTimeout(MyObj.showName.bind(MyObj), 1000)

おすすめ

転載: blog.csdn.net/qq_44721831/article/details/128819504