async/awaitの使用および注意事項

6629 ワード

async / awaitを用いる、promiseと組み合わせることで、同期のようなコードを記述することによって非同期の流れを処理することができ、コードの簡潔性と可読性を高めることができる.本文はasync / awaitの基本的な用法といくつかの注意事項を紹介する.
await
MDNの説明を参照:awaitオペレータは、非同期関数Promiseの内部でのみ使用できるasync functionオブジェクトを待つために使用される.awaitの使用文法は非常に簡単です.
[return_value] = await expression;
expressionは、Promiseオブジェクトまたは待機する任意の値である.await expressionの実行結果には、次のような状況があります.
  • expressionがPromiseオブジェクトである、その値xがfulfilledである場合、戻り値はxである.
  • expressionがPromiseオブジェクトである、異常eでrejectedされると、異常eが投げ出す.
  • expressionがPromiseオブジェクトでない場合、expressionは、expressionの値をfulfilledとするPromiseオブジェクトに処理され、そのPromiseオブジェクトの最終値(すなわちexpressionの値)に戻る.このような用法はあまり意味がないので、実際に使用する場合はawaitの後にPromiseの対象となるようにする.

  • なお、awaitは、Promiseオブジェクトを待つ間にasync functionの実行を一時停止する、Promiseオブジェクト決議の後になってからasync functionの実行を継続する.
    コードを見てみましょう.
    async function foo() {
        var a = await new Promise((resolve) => {
            setTimeout(() => {
                resolve(1);
            }, 2000);
        });
        console.log(a); //  2    : 1
    
        try {
            var b = await new Promise((resolve, reject) => {
                setTimeout(() => {
                    reject(2);
                }, 1000);
            })
        } catch (e) {
            console.log(e); //  3    : 2
        }
    
        //     2       
        var sleep = await new Promise((resolve) => {
            setTimeout(() => {
                resolve('sleep');
            }, 2000);
        });
    
        var c = await 3;
        console.log(c); //  5    : 3
    }
    
    foo();

    async async functionを使用して、非同期関数を定義します.構文は次のとおりです.
    async function name([param[, param[, ... param]]]) { statements }
    asyncの関数の戻り値は特殊である:関数体内のreturnがどんな値であるかにかかわらず、asyncの関数の実際の戻り値は常にPromiseの対象である.詳しくは、asyncの関数のうちreturnに1つの値xがあると、xの値がどのような種類であるかにかかわらず、asyncの関数の実際の戻り値は常にPromise.resolve(x)である.
    では、Promise.resolve(x)は最終的にどのようなpromiseを返しますか?MDNの紹介を見てみましょう.
    Promise.resolve(value)メソッドは、所与の値で解析されたPromiseオブジェクトを返します.しかし、この値がthenable(すなわちthenメソッド付き)である場合、返されるpromiseはこのthenableのオブジェクトを「フォロー」し、その最終状態(resolved/rejected/pending/settledを指す)を採用する.そうでなければ、この値を成功状態としてpromiseオブジェクトを返します.
    次にコードの応用を見ます.まず、要求1によりデータ1を取得する、その後、要求2により送信データ1を携帯することによりデータ2を取得し、データ2を取得してからページに表示するシーンがあるとする.
    シナリオ1:
    async function showData() {
        //       1
        var data1 = await new Promise((resolve) => {
            setTimeout(() => {
                resolve('data1');
            }, 1000);
        });
    
        //       2        1
        var data2 = await new Promise((resolve) => {
            setTimeout(() => {
                resolve('data2');
            }, 1000);
        });
    
        //     2
        console.log(data2);
    }
    
    showData();

    上記のコードは、データ1とデータ2を順次取得する、データ2を示す.async関数が常に1つのpromiseを返す以上、1つのasync関数でデータ2を取得するpromiseを返し、関数を呼び出した後、then方法でデータを取得することもできます.コードは以下の通りです.
    async function getData() {
        //       1
        var data1 = await new Promise((resolve) => {
            setTimeout(() => {
                resolve('data1');
            }, 1000);
        });
    
        //       2        1
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve('data2');
            }, 1000);
        });
    }
    
    getData().then((v) => {
        console.log(v);
    });