ディープダイビング42枚

4962 ワード

ひどうきプログラミング


同期処理と非同期処理


関数を呼び出すと、関数コードが計算され、関数実行コンテキストが生成されます.生成された関数実行コンテキストは、実行コンテキストスタック(呼び出しスタック)にプッシュされ、関数コードが実行されます.関数コードの実行が終了すると、関数実行コンテキストが実行コンテキストからポップアップされ、削除されます.
const foo = () => {}
const bar = () => {}

foo()
bar()

関数を実行するには、コード評価プロセスで作成したdin関数実行コンテキストが、実行コンテキストスタックのバッファになる必要があります.
関数が呼び出し順に実行されるのは、関数が呼び出し順に実行されるコンテキストが実行コンテキストスタックにプッシュされるためです.
JavaScriptの最後に実行コンテキストスタックが1つしかありません.これは、2つの関数を同時に実行できないことを意味します.コンテキストスタックを実行する親要素「実行中の実行コンテキスト」を除いて、すべての実行コンテキストは実行待ちのタスクです.
すなわち、現在実行されている関数が終了すると、実行が開始されます.
このようにJavaScriptエンジンは単一スレッドで動作します.
単一スレッド方式では一度に1つのタスクしか実行できないため、処理時間が必要なタスクを実行すると、ブロック(割り込み)が発生します.
function sleep(func, delay) {
    const delayUntil = Date.now() + delay

    while(Date.now() < delayUntil)
    func()
}

function foo() {
    console.log('foo')
}

function bar() {
    console.log('bar')
}

sleep(foo, 3 * 1000);

bar()
sleep関数は3秒後にfoo関数を呼び出します.このときbar関数はsleep関数の実行が終了した後に呼び出されるので,3秒以上呼び出されてブロックされることはできない.このように、現在実行されているタスクが終了する前に次の実行を待つタスク待ちを同期処理と呼ぶ.同期処理方式ではタスクを逐次処理するため,実行順序は保証されているが,ブロックされるという欠点がある.
function foo() {
    console.log('foo')
}

function bar() {
    console.log('bar');
}

setTimeout(foo, 3 * 1000);
bar();
settimeout関数は、前のsleep関数と同様に、コールバック関数を呼び出しますが、settimeout関数の後のタスクをブロックするのではなく、直接実行します.この方式を非同期処理と呼ぶ.
settimeout関数は、前のsleep関数と同様に、コールバック関数を呼び出しますが、settimeout関数の後のタスクをブロックするのではなく、直接実行します.この方式を非同期処理と呼ぶ.
同期処理方式の利点は、タスクが順番に処理されるため、実行順序を保証できるが、ブロックされるという欠点がある.非同期処理方式はブロックを生じないという利点があるが,タスクの実行順序が保障されていないという欠点がある.
タイマ関数settimeout、setInterval、HTTPリクエスト、イベントハンドラは非同期で動作します.

イベントループとタスクキュー


JAvascriptの特徴の1つは、ブラウザが実行されると、タスクが同時に処理されていると感じられる単一スレッドで実行されることです.たとえば、HTML要素は、アニメーション効果の移動によってイベントを処理したり、HTTPリクエストによってサーバからデータを取得してレンダリングしたりすることができます.このようにJavaScriptの同期性をサポートするのがイベントループである.
イベントループはブラウザに内蔵された機能です.

callスタックとhipからなるJavaScriptエンジンは、タスクを要求するときにcallスタックを介して要求されたタスクを順次実行するだけです.非同期処理では、ソースコードの評価と実行以外のすべての処理は、JavaScriptエンジンを構成する環境ブラウザまたはノードです.jsが担当する.
ex)非同期で実行されるsettimeoutコールバック関数の評価と実行はJavaScriptエンジンが担当するが、コールスケジューリングのタイマー設定とコールバック関数の登録はブラウザまたはノードが担当する.jsが担当する.このため、ブラウザはタスクキューとイベントループを提供します.
function foo() {
    console.log('foo')
}

function bar() {
    console.log('bar')
}

setTimeout(foo, 0); // 실제는 4ms
bar();
上記の例の実行順序は次のとおりです.
1.グローバルコードを評価し、典型的な実行コンテキストを生成し、呼び出しスタックにプッシュする.

  • グローバルコードはsettimeout関数の実行を開始し、呼び出します.settimeout関数の関数実行コンテキストが作成され、呼び出しスタックにプッシュされ、現在実行されている実行コンテキストとなる.ブラウザのWeb APIタイマ関数も実行コンテキストを生成します.

  • SetTimeout関数が実行されると、コールバック関数は呼び出しをスケジュールして終了し、呼び出しスタックからポップアップします.タイマ設定とタイマが期限切れになった場合、コールバック関数をタスクキューにプッシュするのがブラウザの役割です.

  • ブラウザが実行する4-1とJavaScriptエンジンが実行する4-2は並行して処理される.

  • 4-1ブラウザはタイマを設定し、タイマが期限切れになるまで待機し、タイマが期限切れになるとfooはタスクキューにプッシュされます.上記の場合、最小遅延時間4 msを指定します.したがって、4 ms以内にコールバック関数fooがタスクキューにプッシュされて待機する.このようなsettimeout関数を用いてスケジューリングされたコールバック関数は、遅延時間後に呼び出されることを保証できない.

  • 4−2 bar関数を呼び出してbar関数の実行コンテキストを生成し、呼び出しスタックにプッシュして現在の実行コンテキストとする.その後、bar関数は終了し、callスタックでポップアップされます.

  • グローバルコードの実行が終了し、グローバル実行コンテキストが呼び出しスタックからポップアップされ、実行コンテキストが存在しなくなります.

  • イベントループはcallスタックが空であることを検出し、タスクキューで待機しているコールバック関数fooはイベントループによってcallスタックにプッシュされる.
  • settimeoutのコールバック関数はタスクキューにプッシュされ、呼び出しスタックが空になるのを待って(グローバルコードと明示的な呼び出し関数が終了した場合)、呼び出しスタックにプッシュされて実行されます.
    Javaスクリプトは単一スレッドで実行され、ブラウザはマルチスレッドで実行されます.

    整理する


    JavaScriptでの非同期プログラミング


    単一スレッドにはスタックが1つしかないので、1つのことしかできません.単一スレッド環境で同期を実現する方法には、コールバック関数とイベントループがあります.
    非同期関数は、呼び出し後に必要な作業が完了しなくてもすぐに返されます.すぐに返される値には、実際の結果値はありません.

    整理する


    JavaScriptでの非同期プログラミング


    単一スレッドにはスタックが1つしかないので、1つのことしかできません.単一スレッド環境で同期を実現する方法には、コールバック関数とイベントループがあります.
    非同期関数は、呼び出し後に必要な作業が完了しなくてもすぐに返されます.すぐに返される値には、実際の結果値はありません.
    https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif
    JavaScriptエンジンにおける非同期コードの処理方法を上図で説明します.
    実際に処理するコールバック関数(真の結果値)がTask QueueにWeb APIを介してスタックされる必要がある場合、イベントループはCall Stackが空であるかどうかをチェックし、空にします.
    Queueに積み上げられた関数をCallStackに送信し、呼び出します.
    このモードの同期性の問題における自由は,干渉を受けずに処理を継続することにある.コールバック関数が終了すると、イベントループはキュー内の次のイベントまたは
    メッセージを取り出して呼び出し、繰り返します.
    ただし、スレッドに異常が発生すると、そのスレッドのスタックが逆転し、連続的に問題が発生します.そのため、
    知らず知らずに仕事ができる.
    また,イベントループは呼び出しスタックが空の場合に実行されなければならないため,正しい時点で関数を実行しないという懸念がある.