web-dev-qa-db-ja.com

遅延せずにsetTimeoutを呼び出す

次のようなJavaScriptライブラリコードでよく見られます。

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

なぜそのようなラッパーコードを使うのか知りたいのですが。

41
defuz

非常に単純化:

ブラウザはシングルスレッドであり、このシングルスレッド(UIスレッド)はレンダリングエンジンとjsエンジンの間で共有されます。

実行したい処理に長い時間がかかる場合(ここではサイクルを話しますが、それでも)、レンダリングが停止(一時停止)する可能性があります(フローとペイント)。

ブラウザには、すべてのイベントが最初にUIスレッドが何を実行していても終了するのを待つ「バケット」も存在します。スレッドが完了するとすぐに、バケットが検索され、最初にタスクが選択されます。

setTimeoutを使用して、遅延後にバケット内に新しいタスクを作成し、追加の作業に使用できるようになったらすぐにスレッドに処理させます。

ストーリー:

0ミリ秒の遅延の後、関数の新しいタスクを作成し、バケットに配置します。その正確な瞬間に、UIスレッドは何か他のことをするのに忙しく、バケットにはすでに別のタスクがあります。 6ミリ秒後にスレッドが使用可能になり、タスクがあなたの前に表示されます。しかし、何ですか?それは一つの大きなことでした!これまでのように(30ms)!

ついに、今やスレッドはそれで終わり、あなたの仕事をやって来ます。

ほとんどのブラウザでは0以上の最小遅延があるため、遅延として0を指定すると、このタスクをできるだけ早くバスケットに入れます。ただし、UAにできるだけ早くバケットに入れるように指示しても、その時点で実行される保証はありません。バケットは郵便局のようなもので、他のタスクの長いキューがある可能性があります。郵便局もシングルスレッドであり、1人の担当者だけがすべてのタスクをサポートしています。あなたの仕事は、他の皆と同じように並ぶ必要があります。

ブラウザが独自のティッカーを実装していない場合、ブラウザはOSのティックサイクルを使用します。古いブラウザでは、10〜15ミリ秒の最小遅延がありました。 HTML5 は、遅延が4ミリ秒未満の場合、UAが4ミリ秒に増やす必要があることを示しています 。これは、2010年以降にリリースされたブラウザ間で 一貫していると言われています

詳細については、John Resigによる JavaScript Timers Work を参照してください。

編集:も参照してください とにかくイベントループは何ですか? JSConf EU 2014のフィリップロバーツによる。これは、フロントエンドコードに触れるすべての人に必須の表示です。

64
anddoutoi

これを行う理由はいくつかあります

  • すぐに実行したくないが、近い将来に実行したいアクションがあります。
  • setTimeoutまたはsetIntervalから以前に登録された他のハンドラーの実行を許可したい
10
JaredPar

以前の回答とは別に、考えられる別の便利なシナリオを追加したいと思います。try-catchブロックから「エスケープ」することです。 try-catchブロック内からのsetTimeout-delayはブロックの外部で実行され、例外はすべてグローバルスコープに伝播されます。

おそらく最良のシナリオ例:今日のJavaScriptでは、非同期コールバックにいわゆるDeferreds/Promisesがより一般的に使用されているため、実際にはtry-catch内で実行されていることがよくあります。 Deferreds/Promisesは、コールバックをtry-catchでラップして、例外を非同期チェーン内のエラーとして検出および伝播できるようにします。これはチェーン内にある必要のある関数に適していますが、遅かれ早かれ「完了」し(つまり、すべてのajaxをフェッチし)、例外にしたくない場合にプレーンな非同期コードを実行する必要があります。隠された」もう。 AFAIK Dojo、Kris KowalのQ、MochiKit、およびGoogle Closure libは、try-catchラッピングを使用します(ただしjQueryではありません)。

(奇妙な場合には、この手法を使用して、再帰を引き起こさずにシングルトンスタイルのコードを再起動しました。つまり、同じループでティアダウンリスタートを実行します)。

7

前のコードが完了するのを待たずに残りのコードを実行する場合は、setTimeout関数に渡される匿名メソッドにコードを追加する必要があります。それ以外の場合、コードは前の処理が完了するまで待機します

例:

function callMe()
{
   for(var i = 0; i < 100000; i++)
     {
       document.title = i;
     }
} 

var x = 10;
setTimeout(callMe, 0);

var el = document.getElementById('test-id');
el.innerHTML = 'Im done before callMe method';

それが私がそれを使う理由です。

4
Senad Meškin

以前に設定されたタイムアウトを実行できるようにするため。

1
HBP