JavaScriptのPromiseとasync/await

一度理解してもしばらくすると忘れてしまう。






Promise



callback処理を少し使いやすくしたもの。
主に非同期処理に失敗した時の処理が書きやすくなる。


Promiseを作成する



const promise = new Promise((resolve, reject) => {
  // 成功
  resolve(result)
  // 失敗
  reject(err)
})


promise.then( function(result) {
  // 成功時処理
}).catch(function(error) {
  // 失敗時処理
  console.error(error);
});

resolveとthen、rejectとcatvhがそれぞれ対応している。

new Promise(function(resolve){})

Promise.resolve(function(resolve){})
はほぼ等価(例外の扱いが異なる)

引数はPromiseを返しさえすればいいので
Promise.resolve(async function(){})
といった記述も可能(asyncの詳細は後述)



async/await



Promiseに関わる処理を言い換えたもの。
try/catchが使えるなどよりモダンな書き方ができる。


async


関数の先頭につけるとPromiseを返すようになる

下記は同じ処理になる(どちらもPromiseを返す)


function func2(arg) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(arg)
      resolve()
    }, Math.random() * 10)
  })
}
// func2と全く同じ動きになる
async function func3(arg) {
  setTimeout(() => {
    console.log(arg)
  }, Math.random() * 10)
}

await


非同期関数であっても前の処理が終わる(Promiseの結果が返される)まで待つ。
Promise内でのみ記述可能。

サンプルコード

非同期関数の順次処理
async/awaitを利用する理由の全てと言っても過言ではないかもしれない。

function func2(arg) {
  return new Promise<void>(resolve, reject) => {
    setTimeout(() => {
      console.log(arg)
      resolve()
    }, Math.random() * 10)
  })
}

Promise.resolve().then(async function () {
  for (let index = 0; index < 30; index++) {
    // 終了するまで待つ
    await func2(index)
  }
})


非同期関数の一括処理処理
const promise1 = func3(101)
const promise2 = func3(102)
const promise3 = func3(103)

Promise.all([promise1, promise2, promise3])

戻り値は.then(result[])と.catch(err)になる。
上記は以下とほぼ等価。

Promise.resolve().then(async function () {
  for (let index = 101; index < 104; index++) {
    func2(index)
  }
})
戻り値は変数に代入可能。
例外はtry/catchを使用する。




まとめ



非同期処理を作成する場合


ayncをつけるもしくはPromiseを返す。


非同期処理を利用する場合


Promise内でawaitを先頭につける。
PromiseMethod.then(), PromiseMethod.catch()を利用する。
何もしない場合いつ完了するか把握できずまた戻り値も取得できない。




参考



Promiseについて詳細に解説されている。
https://azu.github.io/promises-book/

https://qiita.com/soarflat/items/1a9613e023200bbebcb3

2019年12月9日月曜日