JavaScriptの同期処理 async/awaitを分かりやすく

JavaScriptの面倒くさいところに同期処理が面倒くさいというのがある。

ある処理が終了した後はコールバック関数が非同期で呼ばれるというのがよくあり、ちょっと色々かくとコールバック地獄になる

非同期で動く例

axiosというライブラリを使って、このブログにアクセスするコードを書いてみる。

const axios = require('axios');

const main = ()=>{
    axios.get("https://glorificatio.org/").then(res=>{
        //HTTP ステータスを表示(何もなければ200)
        console.log(res.status);
    });
    console.log("終了");
}

main();

こういうコードの場合、
ウェブページにアクセスする処理をお願いしたら、main関数の処理は先に進み、
先に”終了”という文字を表示させて、
その後にウェブページからのリクエストが帰ってきてHTTPステータスが表示される

なのでこのような表示結果になる
終了
200

async awaitを使って同期をとる

簡単な使い方を説明する

  • .then()で非同期処理になる関数を呼び出す時に、awaitをつける
  • 戻り値がthenに渡すコールバック関数の引数と同じになる
  • awaitが使われる関数にasyncをつける
const axios = require('axios');

const main = async ()=>{
    let res = await axios.get("https://glorificatio.org/")
    console.log(res.status)
    console.log("終了");
}

main();

これでawaitを付けたところ、すなわちaxiosの処理が終わるまでmain関数の処理を待っててくれる

処理結果はさっきとは順番が変わって、ソースコード上の順番になっていて、とてもわかり易くなっている。

処理結果は以下の通り
200
終了

非同期処理を作る

async awaitは非同期処理をする関数がもともとあって、それを同期処理にしたい場合につかう。

逆に、非同期処理を手で作ってみる場合はどうするのか。
さっそくなので作ってみる。
1秒ほどかかってようやく計算をするというメソッドで、
しかもマイナス値だとエラーになるという仕様だ

//非同期な処理をする関数
const osoiProc = (n) =>{
    
    //非同期したい処理はPromiseでくるむ感じ
    return new Promise((resolve,reject) =>{
        let a = 3 * n;
        //時間が遅くなっているのはサンプル的にsetTimeoutで再現
        setTimeout(()=>{
            if(a <= 0) {
                //エラーにしたい場合はrejectに結果を渡す
                reject(a + "はマイナスの数");
            }else {
                //普通の場合はresolveに結果を渡す
                resolve(a);
            }
        },1000)
    });
}

const main =  ()=>{
    osoiProc(5).then(res=>{
        console.log(res);
    }).catch(err=>{
        console.log(err);
    });

    osoiProc(-5).then(res=>{
        console.log(res);
    }).catch(err=>{
        console.log(err);
    });
    console.log("終了");
}

main();

osoiProcが非同期処理の例
Promiseを使っている。

Promiseを使うと、axiosのようにthen等でコールバックを設定し、非同期処理ができる

このコードの場合の結果は以下のようになる
終了
15
-15はマイナスの数

自前の非同期処理でもasync await

promiseを使った非同期処理を呼び出すときにawaitをつければ同じ様に同期処理になる



//非同期な処理をする関数
const osoiProc = (n) =>{
    
    //非同期したい処理はPromiseでくるむ感じ
    return new Promise((resolve,reject) =>{
        let a = 3 * n;
        //時間が遅くなっているのはサンプル的にsetTimeoutで再現
        setTimeout(()=>{
            if(a <= 0) {
                //エラーにしたい場合はrejectに結果を渡す
                reject(a + "はマイナスの数");
            }else {
                //普通の場合はresolveに結果を渡す
                resolve(a);
            }
        },1000)
    });
}

const main =  async ()=>{
    try{
        let res = await osoiProc(5)
        console.log(res);
    }catch(err) {
        console.log("キャッチされた",err);
    }

    try{
        let res = await osoiProc(-5)
        console.log(res);
    }catch(err) {
        console.log("キャッチされた",err);
    }

    console.log("終了")
}

main();

osoiProcは変更なく、呼び出している方が変わる

then()に渡すコールバック関数で取得できる引数は、await付きのメソッドから返される戻り地になる。
エラー時に呼び出されるcatch()のコールバック関数に相当するのは
普通のtry catch構文で対応できるようになっている。

実行結果はこのようになる
15
キャッチされた -15はマイナスの数
終了

コールバックがなくなり、非常にわかりやすい処理になる。

まとめ

  • thenで非同期になっている関数を同期したい場合は、呼び出し時にawaitをつける
  • awaitが登場する関数にasyncをつける
  • 非同期で処理される関数には特に変更を加えることはない

スポンサードリンク

関連コンテンツ