少しぎこちないのsetTimeout

我々はすべて知っているように、このボックスを建てアラート爆弾は、後続のコードの実行をブロックします。

ブラウザ内のJavaScriptコードが実行のシングルスレッドであるためです。言い換えれば、ブラウザは、唯一のメインスレッドは、(ウェブワーカーに関係なく)すべてのJavaScriptコードを実行する責任があります。

前述のブラウザはJavaScript、基本的には3つのだけのソース:

  • BOMのAPIコード、我々はブラウザが提供する能力を操作して利用できるように、

  • DOM APIコード、我々は、Webコンテンツを操作できるように

  • ECMAScriptのための私たち自身のコードを書きます

これは何もありません。我々はまた、知っているようなコードの実装のタイミングとして「時間」のためのsetTimeoutのコードを、その3秒後(機能)することができます:

もちろん、我々はすべて知っている、setTimeoutを「時間」は正確ではない、それだけで保証することができます3秒でdelayCode機能を後に 3秒後として、実行長く待たなければならないことは問題ではありません同じように、実行します。

その関係とは何ですか?私たちは、タスクキュー/ JavaScriptのイベントループが非同期タスクを実行するためのメカニズムであることを知っています。BOMのAPIとしてのsetTimeout、それはタスクキューに実行する機能を追加するために、タイマー、ポイントを設定するための責任があります。だから、タスクを完了すること。そして、タスクキューに機能を追加することが即時実行を保証するものではありません。ときに実行することができます。この機能は、メインスレッドにディスパッチされたときにイベントループに依存します。メインスレッドがアイドル状態であることを前提に、非同期イベントループ機能をスケジュールします。メインスレッドがブロックされている場合、関数はイベントキューに追加されている場合でも、イベントループは、メインスレッドにすぐにそれを派遣しません。これは、setTimeoutを正確なタイミングの理由は、関数を実行することはできません。

あなたのコードの依存関係があれば明らかに、正確なタイミングロジックをsetTimeoutメソッド、それは恥ずかしいことも可能です。絶対にわからない限り、この目的の書き込みコードについては、我々は我々自身に依存しないように努めなければならないsetTimoutの正確なタイミング。しかし、問題は、我々はそれに依存しない独自のコードを書くことを保証することができるということです、我々のコードがそれに依存しない、サードパーティのコードに依存していることを保証することは困難です。

小さなケース

ここでは、この厄介な出会いに本当のケースを紹介しています。非常に単純な関与この場合の機能は、jQueryのあるデータのロードに失敗した$アヤックス()関数再送要求。その依存タイムアウト論理のため失敗タイムアウト設定で得られた、正確なタイミングのsetTimeout。

関連するコードは、3つの主要な機能を含む、また非常に簡単です: 

asyncRequest関数(){ 
  $アヤックス({ 
    URL: 'https://api.example.rs'、
    タイムアウト:15 
  })。次いで(成功、失敗)
} 

関数成功(データ){ 
  //通常の処理データ
} 

関数失敗(XHR、errtext、必須errthrown){ 
  //再送要求
  asyncRequest()
  //プロンプトボックスシェル、メイン処理ブロック
  アラート( '要求タイムアウトを')
} 
//最初のコール
asyncRequest()

 

  • asyncRequest:関数がAjaxリクエストが含まれている、に失敗再び呼び出します。

  • 成功:成功のAjaxコールバック要求

  • 失敗:Ajaxのコールバック要求が失敗しました

通常のロジックはこれです:呼び出しasyncRequestは、要求を送信し、成功するブラウザ成功は、タスクキューに追加ブラウザがします失敗したタスクキューに追加することはできません。イベントループの後、メインスレッドにそれらをディスパッチします。成功は、通常のデータ処理であり、まず呼び出します失敗し、その後呼び出し、asyncRequest再送要求を警告ボックスが殻を求めるプロンプトが表示されます。

Ajaxリクエストの周りの試験環境は、100ミリ秒を返すことがあります。タイムアウトの背後にあるロジックをテストするためには、我々は意図的に一定の時間を確保するために、15ミリ秒にタイムアウト。実際のテスト、うち最初の要求時間が、行くと枝、再送要求、爆弾ボックス、問題はないと失敗します。しかし、マウスは箱の殻を閉じるためにクリックし、彼らが正常復帰の再送要求を見つけて、タイムアウトのためキャンセルされていません。繰り返しのテストが真です。

これは、なぜ最後に、恥ずかしいのですか?発見、jQueryのコードは、このような(https://j11y.io/jquery/#v=git&fn=jQuery.ajax)ということであるタイムアウト要求を殺します:

言い換えれば、我々はセットケースタイムアウトオプションを、jQueryがでます(中断するために実行さ15ミリ秒タイマの後にsetTimeout関数を設定ABORT)要求を、我々は呼んで割り込み機能を

通常の状況下では、上記のコードを実行した後、ブラウザ機能は、15ミリ秒後に中断タスクキューに追加されます。イベントループ機能をすぐに実行するためにメインスレッドにディスパッチされますメインスレッドがアイドル状態の場合は、この時点で、要求は、ブラウザをし、キャンセルされたメインスレッドにそれを派遣する、タスクキューを失敗するイベントループを追加します。これは、への最初の呼び出しであるasyncRequetの状況。

2回目の呼び出し任意の異なる時間asyncRequest?違いは、完全なコールということでもボックスをプレイasyncRequestした後は、メインスレッドをブロックしました。コール前にasyncRequestの結果を、ブラウザはまだ15ミリ秒後にタスクキュー割り込み機能に追加されます。メインスレッドが原因占有状態で爆弾ボックスにブロックされているので、しかし、ここで注意することは、この時点では、イベントループは待つことができます。私たちは、ボックスが閉じ爆撃し、メインスレッドを解放するために1秒か2秒を過ごすまで、マウスを保持し、割り込み機能は、メインスレッド上で実行するようにスケジュールされます。しかし、この前に、Ajaxリクエストすでに成功したリターン、ブラウザがする間、タスクキューに成功を追加します。

理論的には、帰国後のAjaxリクエストjqXHRは(状態のXMLHttpRequest)オブジェクトは変更すべきではない(何の意味を変更しません)。そのため、割り込み機能の実装は、この事実「要求が成功リターン、となっている」変更されません。もっと恥ずかしいことである-割り込み機能が実行された後、イベントループ再び続くメインスレッドに成功スケジューリング機能。失敗関数は、ジョブキューを入力し、ましてや実装されていませんでした。

小さな収穫

上記のケーススタディを通じて、我々は、割り込み機能を実行中のタスクキュー遅延に遅れたが、最終的に成功した戻りデータされているので、この「タイムアウト」のリクエストが失敗したことを参照してください。もちろん、問題の根はである爆弾がメインスレッドだけでなく、非同期JavaScriptのメカニズム(イベントループ)をブロックし、アラートボックス。

jQueryのためとして頼る限り、状況はそう長く何の問題もありませんメインプロセスをブロックし、この記事のようなケースに遭遇していないとして、キャンセルのsetTimeoutロジックタイムアウト要求を。この場合には、そうでない場合は、テストのために、その後、タイムアウトが短すぎる設定されているが、例えば5000ミリ秒に設定され、この厄介な状況が発生しません。実際のサーバーの応答時間が本当に5秒以上である場合には、限り、我々は返すようAjaxリクエストで再生する前にボックスをオフにし、割り込み機能はまだ、それによって未処理の要求を排除し、最初のステップを実行します。もちろん、実際に爆弾ボックスシステムの使用が主なプロセスはお勧めではありませんブロックされているだろう。

とにかく、偶然、私たちはの深い理解、この少しぎこちない取る(または追体験)のsetTimeoutとさえJavaScriptを非同期コード執行メカニズムの(ブラウザがJavaScriptランタイムを提供することを指摘しておかなければ)。だから、次のプログラミングの練習では、我々は意識的にロジックが依存を避けることができ、そのタイミングが本当に信頼性がああではないので、正確なタイミングのsetTimeoutを!

おすすめ

転載: www.cnblogs.com/axl234/p/11303455.html