javascriptのスレッド問題、コレクション
4720 ワード
JavaScriptのsetTimeoutとset Intervalは他の人の感情をだましやすい方法です.私たちはよく呼び出したら既定の方式で実行すると思っています.多くの人が共感していると思います.
set Timeout(function(){alert]、}、0);set Interval(calbackFunction、100)
setTimeoutでの挨拶方法はすぐに実行されると考えられています.これは無条件で言うのではなく、JavaScript API文書で第二のパラメータの意味を明確に定義しています.第二のパラメータは何分間隔であるかを指定すると、コールバック方法が実行されます.ここで0ミリ秒に設定すれば、すぐに実行されるのは当然です.同じ理由でsetIntervalのcalbackFunctメソッドは100ミリ秒間隔ですぐに実行されます.
しかし、JavaScriptの応用開発経験が豊富になるにつれて、ある日あなたは不思議なコードを発見しました.
div.onclick=function(){set Timeout}
ミリ秒後に実行されるなら、setTimeoutで何をするかは、今、確固たる信念が揺れ動き始めています.最後の日まで、あなたは誤って悪いコードを書きました.
set Timeout(function(){while}、100);set Timeout(function(){alert}200);set Interval(calbackFunction、200)
第一行コードは死の循環に入りましたが、まもなく発見されます.第二、第三行は予想されていたことではないです.alert挨拶はまだありません.calbacKFunctionも音信がありません.
この時、あなたは完全に困惑しました.このような情景は受け入れにくいです.長い間既定の認識を変えて新しい思想を受け入れる過程は苦痛です.しかし、情の事実は目の前に置いて、JavaScript真理に対する探求は苦痛のため停止することはありません.
雲霧を切り
上のすべてのエラーが発生した主な原因は、JavaScriptエンジンが複数のスレッドで実行されているという潜在意識の中で、JavaScriptのタイマーコールバック関数は非同期で実行されていると考えられています.
実際には、JavaScriptはカムフラージュを使用しています.多くの時に私たちの目を欺きました.ここでバックライトは一つの事実を明らかにしなければなりません.
JavaScriptエンジンはシングルスレッドで実行されています.ブラウザはいつでも1つのスレッドだけがJavaScriptプログラムを実行しています.
JavaScriptエンジンは単スレッドで実行することも意味があり、単スレッドはスレッド同期などの複雑な問題を無視して、問題を簡略化する必要があります.
単一スレッドのJavaScriptエンジンはどのようにブラウザのカーネルに協力してこれらのタイマーと応答ブラウザのイベントを処理しますか?ブラウザのカーネル処理方法について簡単に説明します.
ブラウザカーネルの実装により、複数のスレッドが非同期で実行されるようになりました.これらのスレッドは、カーネルコントロールの下で互いに協力して同期を維持しています.あるブラウザカーネルの実現には少なくとも3つの常駐スレッドがあります.javascriptエンジンスレッド、インタフェースレンダリングスレッド、ブラウザイベントトリガスレッドなどがあります.他にも、一部の実行が完了したら終了するスレッドがあります.Http要求スレッドなどです.これらの非同期スレッドは、異なる非同期イベントを発生します.以下は、単一スレッドのJavaScriptエンジンと他のスレッドとの間でどのようにインタラクティブ通信が行われているかを図で説明します.各ブラウザのカーネル実装の詳細は異なりますが、その中の呼び出し原理は同じです.
図から分かるように、ブラウザ内のJavaScriptエンジンはイベントに基づいて駆動されています.ここでのイベントは、ブラウザから送信された様々なタスクと考えられます.これらのタスクは、JavaScriptエンジンが現在実行しているコードブロックから発生することができます.setTimeoutを呼び出してタスクを追加すると、ブラウザ内のコアから他のスレッドを追加することもできます.非同期要求状態変更通知など.コードの観点から見れば,タスクエンティティは各種のコールバック関数であり,JavaScriptエンジンは常にジョブキューにおけるタスクの到来を待っている.
上の図t 1-t 2.tnは、異なる時点を示しており、tnの下の対応するブロックは、その時点のタスクを表しており、t 1の時点でエンジンがt 1に対応するタスクブロックコード内を実行していると仮定して、この時点で、ブラウザ内核他のスレッドの状態を説明する.
t 1時刻:
GUIレンダリングスレッド:
このスレッドはブラウザのインターフェースHTML要素をレンダリングしています.インターフェイスが再描画する必要がある場合や、ある操作によってフィードバックが発生する場合には、このスレッドが実行されます.本文ではJavaScriptタイミングメカニズムを重点的に説明しますが、この時には、JavaScriptエンジンスレッドと相互反発するスレッドが必要です.これは分かりやすいです.JavaScriptスクリプトはDOM元素を操作することができます.これらの要素属性を修正しながら界面をレンダリングすると、レンダリングスレッドの前後で得られた要素データが一致しない可能性があります.
JavaScriptエンジンがスクリプトを実行している間、ブラウザのレンダリングスレッドはすべてハングアップ状態、つまり「凍結」されました.
したがって、スクリプトでは、ノードを追加したり、结点を削除したり、结点の外観を変更したりするなどのインターフェースの更新が実行されます.これらの操作は、列に保存されます.JavaScriptエンジンが暇なときにのみレンダリングされます.
GUIイベントトリガスレッド:
JavaScriptスクリプトの実行は、html要素イベントのトリガに影響しません.t 1時間以内に、まずユーザがマウスボタンをクリックし、ブラウザイベントに触発されたスレッドをクリックして、マウスクリックイベントを形成します.JavaScriptエンジンスレッドにとって、このイベントは他のスレッドからタスクのキューの最後に非同期的に渡されます.このマウスクリックイベントは処理を待っています.
タイミングトリガスレッド:
ここのブラウザモデルのタイミングカウンタはJavaScriptエンジンによってカウントされていません.JavaScriptエンジンはシングルスレッドであり、ブロックスレッド状態では計算できない場合、外部に依存してタイミングを計ってトリガしなければならないので、キューの中のタイミングイベントも非同期イベントです.
図から分かるように、このt 1の時間帯において、マウスクリックイベントのトリガに続き、以前設定されていたsetTimeoutタイミングも到来しました.今はJavaScriptエンジンにとって、タイミングトリガスレッドが異常なタイミングイベントを発生し、タスクキューにセットされています.このイベントはイベントのコールバックをクリックした後、処理を待ちます.次のsetIntervalタイマーも追加されました.間隔タイミングなので、t 1セグメント内で連続的に2回トリガされました.この2つのイベントは、列の最後に並べて処理を待ちます.
このように、期間t 1が非常に長く、set Intervalのタイミング間隔よりも遥かに大きい場合、タイミングトリガスレッドは、処理されているかどうかにかかわらず、非同期タイミングイベントを継続的に発生し、処理されているが、t 1と最初のタイミングイベントの前のジョブが処理済みとなると、これらの配列中のタイミングイベントは、順次継続的に実行されることができる.JavaScriptエンジンにとっては、処理キューにおける各タスクの処理方式は同じであり、処理の順序が異なるだけである.
t 1以降、つまり、現在処理されているジョブが戻ってきました.JavaScriptエンジンは、現在のキューが空ではないことを確認し、t 2以下の対応するタスクを取り出して実行します.他の時間はこのように類推します.
キューが空でない場合、エンジンはキューの先からタスクを取り出し、そのタスクが完了するまでは、エンジンを返して次のタスクを実行します.タスクが前のキューに戻らない場合は、他のタスクは実行されません.
JavaScriptがマルチスレッドであるかどうかはすでにお分かりになっていると思います.JavaScriptタイマーの動作メカニズムも理解しています.いくつかのケースを分析します.
ケース1:setTimeoutとsetInterval
ケース2:ajax非同期要求は本当に非同期ですか?
多くの学友の友達ははっきりしないで、JavaScriptが単一スレッドの運行だと言う以上、XMLHttpRequestは接続後に本当に非同期ですか?要求は確かに非同期ですが、この要求はブラウザによって新たにスレッド要求(上の図を参照)が開かれ、要求の状態が変更された場合、以前にリマインドが設定されている場合、この非同期スレッドは状態変更イベントを発生し、JavaScriptエンジンの処理待ち行列に入れて処理されます.ジョブが処理されると、JavaScriptエンジンは常にシングルスレッドでリピート関数を実行します.具体的な点は、シングルスレッドでオンリーシステムを実行するために設定された関数です.
set Timeout(function(){alert]、}、0);set Interval(calbackFunction、100)
setTimeoutでの挨拶方法はすぐに実行されると考えられています.これは無条件で言うのではなく、JavaScript API文書で第二のパラメータの意味を明確に定義しています.第二のパラメータは何分間隔であるかを指定すると、コールバック方法が実行されます.ここで0ミリ秒に設定すれば、すぐに実行されるのは当然です.同じ理由でsetIntervalのcalbackFunctメソッドは100ミリ秒間隔ですぐに実行されます.
しかし、JavaScriptの応用開発経験が豊富になるにつれて、ある日あなたは不思議なコードを発見しました.
div.onclick=function(){set Timeout}
ミリ秒後に実行されるなら、setTimeoutで何をするかは、今、確固たる信念が揺れ動き始めています.最後の日まで、あなたは誤って悪いコードを書きました.
set Timeout(function(){while}、100);set Timeout(function(){alert}200);set Interval(calbackFunction、200)
第一行コードは死の循環に入りましたが、まもなく発見されます.第二、第三行は予想されていたことではないです.alert挨拶はまだありません.calbacKFunctionも音信がありません.
この時、あなたは完全に困惑しました.このような情景は受け入れにくいです.長い間既定の認識を変えて新しい思想を受け入れる過程は苦痛です.しかし、情の事実は目の前に置いて、JavaScript真理に対する探求は苦痛のため停止することはありません.
雲霧を切り
上のすべてのエラーが発生した主な原因は、JavaScriptエンジンが複数のスレッドで実行されているという潜在意識の中で、JavaScriptのタイマーコールバック関数は非同期で実行されていると考えられています.
実際には、JavaScriptはカムフラージュを使用しています.多くの時に私たちの目を欺きました.ここでバックライトは一つの事実を明らかにしなければなりません.
JavaScriptエンジンはシングルスレッドで実行されています.ブラウザはいつでも1つのスレッドだけがJavaScriptプログラムを実行しています.
JavaScriptエンジンは単スレッドで実行することも意味があり、単スレッドはスレッド同期などの複雑な問題を無視して、問題を簡略化する必要があります.
単一スレッドのJavaScriptエンジンはどのようにブラウザのカーネルに協力してこれらのタイマーと応答ブラウザのイベントを処理しますか?ブラウザのカーネル処理方法について簡単に説明します.
ブラウザカーネルの実装により、複数のスレッドが非同期で実行されるようになりました.これらのスレッドは、カーネルコントロールの下で互いに協力して同期を維持しています.あるブラウザカーネルの実現には少なくとも3つの常駐スレッドがあります.javascriptエンジンスレッド、インタフェースレンダリングスレッド、ブラウザイベントトリガスレッドなどがあります.他にも、一部の実行が完了したら終了するスレッドがあります.Http要求スレッドなどです.これらの非同期スレッドは、異なる非同期イベントを発生します.以下は、単一スレッドのJavaScriptエンジンと他のスレッドとの間でどのようにインタラクティブ通信が行われているかを図で説明します.各ブラウザのカーネル実装の詳細は異なりますが、その中の呼び出し原理は同じです.
図から分かるように、ブラウザ内のJavaScriptエンジンはイベントに基づいて駆動されています.ここでのイベントは、ブラウザから送信された様々なタスクと考えられます.これらのタスクは、JavaScriptエンジンが現在実行しているコードブロックから発生することができます.setTimeoutを呼び出してタスクを追加すると、ブラウザ内のコアから他のスレッドを追加することもできます.非同期要求状態変更通知など.コードの観点から見れば,タスクエンティティは各種のコールバック関数であり,JavaScriptエンジンは常にジョブキューにおけるタスクの到来を待っている.
上の図t 1-t 2.tnは、異なる時点を示しており、tnの下の対応するブロックは、その時点のタスクを表しており、t 1の時点でエンジンがt 1に対応するタスクブロックコード内を実行していると仮定して、この時点で、ブラウザ内核他のスレッドの状態を説明する.
t 1時刻:
GUIレンダリングスレッド:
このスレッドはブラウザのインターフェースHTML要素をレンダリングしています.インターフェイスが再描画する必要がある場合や、ある操作によってフィードバックが発生する場合には、このスレッドが実行されます.本文ではJavaScriptタイミングメカニズムを重点的に説明しますが、この時には、JavaScriptエンジンスレッドと相互反発するスレッドが必要です.これは分かりやすいです.JavaScriptスクリプトはDOM元素を操作することができます.これらの要素属性を修正しながら界面をレンダリングすると、レンダリングスレッドの前後で得られた要素データが一致しない可能性があります.
JavaScriptエンジンがスクリプトを実行している間、ブラウザのレンダリングスレッドはすべてハングアップ状態、つまり「凍結」されました.
したがって、スクリプトでは、ノードを追加したり、结点を削除したり、结点の外観を変更したりするなどのインターフェースの更新が実行されます.これらの操作は、列に保存されます.JavaScriptエンジンが暇なときにのみレンダリングされます.
GUIイベントトリガスレッド:
JavaScriptスクリプトの実行は、html要素イベントのトリガに影響しません.t 1時間以内に、まずユーザがマウスボタンをクリックし、ブラウザイベントに触発されたスレッドをクリックして、マウスクリックイベントを形成します.JavaScriptエンジンスレッドにとって、このイベントは他のスレッドからタスクのキューの最後に非同期的に渡されます.このマウスクリックイベントは処理を待っています.
タイミングトリガスレッド:
ここのブラウザモデルのタイミングカウンタはJavaScriptエンジンによってカウントされていません.JavaScriptエンジンはシングルスレッドであり、ブロックスレッド状態では計算できない場合、外部に依存してタイミングを計ってトリガしなければならないので、キューの中のタイミングイベントも非同期イベントです.
図から分かるように、このt 1の時間帯において、マウスクリックイベントのトリガに続き、以前設定されていたsetTimeoutタイミングも到来しました.今はJavaScriptエンジンにとって、タイミングトリガスレッドが異常なタイミングイベントを発生し、タスクキューにセットされています.このイベントはイベントのコールバックをクリックした後、処理を待ちます.次のsetIntervalタイマーも追加されました.間隔タイミングなので、t 1セグメント内で連続的に2回トリガされました.この2つのイベントは、列の最後に並べて処理を待ちます.
このように、期間t 1が非常に長く、set Intervalのタイミング間隔よりも遥かに大きい場合、タイミングトリガスレッドは、処理されているかどうかにかかわらず、非同期タイミングイベントを継続的に発生し、処理されているが、t 1と最初のタイミングイベントの前のジョブが処理済みとなると、これらの配列中のタイミングイベントは、順次継続的に実行されることができる.JavaScriptエンジンにとっては、処理キューにおける各タスクの処理方式は同じであり、処理の順序が異なるだけである.
t 1以降、つまり、現在処理されているジョブが戻ってきました.JavaScriptエンジンは、現在のキューが空ではないことを確認し、t 2以下の対応するタスクを取り出して実行します.他の時間はこのように類推します.
キューが空でない場合、エンジンはキューの先からタスクを取り出し、そのタスクが完了するまでは、エンジンを返して次のタスクを実行します.タスクが前のキューに戻らない場合は、他のタスクは実行されません.
JavaScriptがマルチスレッドであるかどうかはすでにお分かりになっていると思います.JavaScriptタイマーの動作メカニズムも理解しています.いくつかのケースを分析します.
ケース1:setTimeoutとsetInterval
setTimeout(function(){
/* ... */
setTimeout(arguments.callee, 10);
}, 10);
setInterval(function(){
/* ... */
}, 10);
この二つのコードは効果が同じです.実は非也、第一段の中でコールバック関数内のsetTimeoutはJavaScriptエンジンの実行後に新しいセットTimeoutタイミングを設定します.前回のコールバック処理が終わったら、次のコールバック開始処理までは時間間隔と仮定して、理論の二つのsetTimeoutコールはタイム間隔を実行します.タイミングトリガスレッドは、10秒ごとに非同期タイミングイベントを発生させ、タスクの列の最後に置くと、理論的に2つのsetIntervalコールコールが実行される時間間隔(=10.ケース2:ajax非同期要求は本当に非同期ですか?
多くの学友の友達ははっきりしないで、JavaScriptが単一スレッドの運行だと言う以上、XMLHttpRequestは接続後に本当に非同期ですか?要求は確かに非同期ですが、この要求はブラウザによって新たにスレッド要求(上の図を参照)が開かれ、要求の状態が変更された場合、以前にリマインドが設定されている場合、この非同期スレッドは状態変更イベントを発生し、JavaScriptエンジンの処理待ち行列に入れて処理されます.ジョブが処理されると、JavaScriptエンジンは常にシングルスレッドでリピート関数を実行します.具体的な点は、シングルスレッドでオンリーシステムを実行するために設定された関数です.