JavaScript

JS基礎ー非同期とコールバック

初めに

自分は業務中でよくPromiseで非同期処理を実現しますが、そもそもなぜPromise使うのかをよくわからないので、今回は基礎からJavaScriptの非同期とコールバックについて整理してみます。

先ずは定義

非同期処理:JSにおける非同期処理は、プログラムコードを上から順に1行ずつ実行していきません
コールバック:他のコードの引数として渡されるサブルーチンである

function A(callback){
    console.log("I am A");
    callback();  //渡されるサブルーチン
}

function B(){
   console.log("I am B");
}

A(B);

非同期処理とコールバック

コールバックは非同期処理を実現するの手段の一つであり、逆にコールバックで実装したコードは必ず非同期処理とは言えません。
上の例がコールバックで同期処理の例です。
で、次は非同期処理を見にいきましょうか。
また、以下のような関数があります

f1() // 時間をかかる
f2() // f1の次の番実行する
f3() // f1,f2と関係ない、できれば早めに実行する

f1の実行に時間がかかるのため、f2とf3は待つしかない

コールバックで非同期させます:

function f1(callback){
    setTimeout(function () {
        // do some thing
        callback();
    }, 1000);
}

f1(f2);

f3();

こういう書き方だと、setTimeoutを使ってf1を非同期処理させ、f3を早めに実行できるようになりました。

なぜ非同期なのか?

JavaScriptの特徴の一つにシングルスレッドがあります。
であれば、どうやって一つスレッドしかを使わないで非同期を実現する?
答えはEvent Loopとのことです。
event-loop.png
(event-loopのインメージ from 「Help, I’m stuck in an event-loop」

要するに、JavaScriptの実行順番は下記となります:
➀:heap、stackを生成する
②:stack中のコードを外部apiを呼び出し、イベント(click,load,done)をcallback queueに追加する
③:stack中のコードの実行が終わったら、callback queue内のcallback functionをstackに投げる
④:step➀に戻る

ですので、上記の例で、f1()をsetTimeout経由でcallback queueに追加し、とりあえずf3()を実行します。
要注意:setTimeoutの設定通り、1000ms後、コールバック関数を実行ではなくて、callback queueに追加するだけです。

まとめ

今回は基礎からJavaScriptの非同期とコールバックについて整理し、非同期処理の流れが明確になりました。