技術メモなど

業務や日々のプログラミングのなかで気になったことをメモしています。PHP 成分多め。

JavaScriptのasync/waitについて調べた

JavaScript再入門中。 今回はasync/waitについてメモ。

async/waitとは

async function 宣言は、 AsyncFunction オブジェクトを返す 非同期関数 を定義します。非同期関数は非同期でイベントループを介して実行され、暗黙的にPromiseを返します。なおコードのシンタックス及び構造は通常の同期関数と非常に似たものになります。
async function - MDN

await 演算子は、async function によって Promise が返されるのを待機するために使用します。
wait - MDN

async/awaitを利用することで、Promise処理をより簡潔に書くことができる。

async function

async functionは、関数定義の前にasyncキーワードをつけて宣言する。

// async functionの定義
var asyncFunc = async function () {
  return 1;
}

// async functionは実行するとPromiseオブジェクトを返却する
asyncFunc().then( console.log );
// 1

async関数は、returnで終了した場合はresolveされた、throwで終了した場合はrejectされたPromiseオブジェクトを返却する。 また、自前で作成したPromiseオブジェクトを返却することもできる。 以上から、async関数の戻り値はPromiseオブジェクトであることが保証される。

var asyncFunc1 = async () =>{ return 1 };
asyncFunc1()
    .then( v => console.log(`then: ${v}`) )
    .catch( v => console.log(`catch: ${v}`) );
// then: 1

var asyncFunc2 = async () =>{ throw new Error('error')};
asyncFunc2()
    .then( v => console.log(`then: ${v}`) )
    .catch( v => console.log(`catch: ${v}`) );
// catch: Error: error

// returnを明示しなかった場合はresolveになる
var asyncFunc3 = async () =>{ };
asyncFunc3()
    .then( v => console.log(`then: ${v}`) )
    .catch( v => console.log(`catch: ${v}`) );
// then: undefined

// 明示的にPromiseオブジェクトを返却することもできる
var asyncFunc4 = async () => Promise.resolve(4);
asyncFunc4()
    .then( v => console.log(`then: ${v}`) )
    .catch( v => console.log(`catch: ${v}`) );
// then: 4

var asyncFunc5 = async () => Promise.reject(5);
asyncFunc5()
    .then( v => console.log(`then: ${v}`) )
    .catch( v => console.log(`catch: ${v}`) );
// catch: 5

await

awaitキーワードは、async関数の実行を一時停止させ、Promiseの解決または拒否を待機する。

var asyncFunc = async () => {
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("success!"), 1000)
  });

  let result = await promise; // promise が解決するまで待機

  console.log(result);
}

asyncFunc();
// success!

awaitキーワードは、async関数以外の箇所では宣言できない。
グローバルや、通常の関数内部で実行するとシンタックスエラーが発生する。

// 通常の関数内部では使用できない
var func = function(){
    let promise  = await new Promise((resolve, reject) => {});
    await promise; // Error: await is only valid in async function
}

awaitに渡されたPromiserejectされた場合、通常の例外のように値がスローされる。 スローされた値は、例外のようにtry..catchでキャッチできる。 また、Promise.catchメソッドで処理することもできる。

// try..catch構文を使って処理
var asyncFunc1 = async () => {
  try {
    var foo = await Promise.reject(new Error('failed..')); // Errorオブジェクトがスローされる
  } catch (e) {
    console.log(e);
  }
}
asyncFunc1();
// Error: failed..

// catchメソッドを使っても処理できる
var asyncFunc2 = async () => {
    var z = await Promise.reject(new Error('failed..')).catch(console.log);
}
asyncFunc2();
// Error: failed..

記事中のコードは以下にまとめてあります。
async/wait調査 · GitHub

参考文献