echo("備忘録");

IT技術やプログラミング関連など、技術系の事を備忘録的にまとめています。

【Javascript】非同期処理のPromiseやasync/awaitについて その2

前回はPromiseについて書きましたが、その続きで今回はasync/awaitについて。

【参考】
async/await 入門(JavaScript)

asyncとは

非同期関数を定義する関数宣言のこと。
async関数は、以下の動作をする。

  • Promiseを返す
  • 値をreturnすると、Promiseはそれをresolveする。
  • エラーなどをスローすると、Promiseはそれをrejectする。
  • 関数内部でawaitを使用できる。
// 普通こんな書き方しませんが、サンプルということで。  
function main() {  
    
    const even = checkEven(2);
  
    // この場合、コンソールには「偶数です」と表示される。
    even.then((message) => {
        console.log(message);
    }).catch((err) => {
        console.log(err.message);
    });
  
    const odd = checkEven(1);
  
    // この場合、コンソールには「奇数です!」と表示される。
    odd.then((message) => {
        console.log('偶数です');
    }).catch((err) => {
        console.log(err.message);
    });
}
  
async function checkEven(num) {
    if(num % 2 === 0) {
        // resolve('偶数です')と同じ。
        return '偶数です';
    } else {
        // reject('奇数です!')と同じ。
        throw new Error('奇数です!');
    }
}

awaitとは

  • Promiseを返す関数について、Promiseの結果(resolveやreject)が返されるまで、処理を待つ。
    • 同期処理みたいな動作になる。
  • awaitを付けた場合、戻り値に格納されるのはresolve、あるいはrejectされた値となる。
  • rejectされたのがエラー場合、そのエラーが発生する。(catch()処理などを実施する必要あり)
  • async関数内でのみ使用できる。

先程の関数を、awaitを使って書くと、こうなります。

async function main() {  
    
    // この場合、messageにはresolve値の「偶数です」が格納されるので、  
    // それがそのまま表示される。
    try {
        const even = await checkEven(2);
        console.log(even);
    } catch(err) {
        console.log(err.message);
    }
  
    // この場合、checkEvenからErrorがスローされるので、コンソールには  
    // err.message(「奇数です!」)が表示される。
    try {
        const odd = await checkEven(1);
        console.log(odd);
    } catch(err) {
        console.log(err.message);
    }
}
  
async function checkEven(num) {
    if(num % 2 === 0) {
        // resolve('偶数です')と同じ。
        return '偶数です';
    } else {
        // reject('奇数です!')と同じ。
        throw new Error('奇数です!');
    }
}

await使用時の注意点

  • awaitは基本的に「resolveの値がないと、それ以降の処理ができない」際に使用する。(下記など)
    • ファイルの内容を取得する
    • DBのあるテーブルのレコードを取得する
  • awaitは先述の通り「Promiseの結果が返されるまで、処理を待つ」動作。
    • async関数だからと言って、なんでもawaitすればいいわけではない。
    • 使い方を間違えると、レスポンス時間の遅延につながる。(下記ソース)
async function main() {  
    
    // funcVal1~funcVal3が「それぞれ処理に5秒かかる」場合、  
    // awaitで直列処理してしまうと、main()が終わるのに15秒かかってしまう。  
    try {
        const val1 = await funcVal1();
        const val2 = await funcVal2();
        const val3 = await funcVal3();
    } catch(err) {
    }
  
    // この場合、await は使わず、Promise.all()を使って並列処理すれば  
    // main()が終わるのは5秒で済む。
    const func1 = funcVal1();
    const func2 = funcVal2();
    const func3 = funcVal3();
  
    Promise.all([func1, func2, func3]).then(([val1, val2, val3]) => {
        // すべて正常終了した際の処理
    }).catch((err) => {
        // どれか一つでもErrorがスローされた際の処理
    });
}

また急ぎ足気味になってしまいましたが、今日はこの辺で。