ぬぬん!

やってみたこと,思ったこと

 Promiseしか知らなかったけどasync/awaitを調べて使ってみた

JSの話です

非同期処理苦手だわー(白目) で日頃生きており
やっと最近Promiseが使えるかな(?)になったところ
async/awaitという未知の存在に遭遇したということで
遅いながらも、ちゃんと知っておかなきゃと思い
調査と実際に手を動かしてみたという自分メモの記事です

内容的にはインターネット上でn( n > 10)番煎じ

Promise

Promise オブジェクトは非同期処理の最終的な完了処理(もしくは失敗)およびその結果の値を表現します。

developer.mozilla.org

よく使うのは
なんかしらwebAPIを叩いていて
そのレスポンスの値に応じて処理をしたい場合とかだと思う
(fetch()は実質Promiseを返してるし実際API叩くならfetchが良さそう)

const apiResponse = new Promise((resolve, reject) => {
  const xhr = new XMLHttpRequest(),
    method = "GET",
    url = "https://api.zipaddress.net/?zipcode=900-0012"

  xhr.open(method, url, true)
  xhr.onreadystatechange = function () {
    if(xhr.readyState === 4 && xhr.status === 200) {
      resolve(xhr.response)
    }
  };
  xhr.responseType = 'json'
  xhr.send()
})

apiResponse.then((val) => {
  if (val.data.pref === '沖縄県') {
    console.log('はいさい')
  } else {
    console.log('うぇい')
  }
}).catch((error) => {
  console.log('error:' + error)
})

console.log(apiResponse)

これの結果は

Promise {<pending>}
はいさい

となる。

実行順番は
console.log(apiResponse) -> apiResponse.then() の順で実行されて

console.log(apiResponse) が実行されるときには、
まだAPIのレスポンスが帰ってきてないので
Promiseオブジェクトでpendingというステータスが表示されている

apiResponse.then()実行されるときには、もうレスポンスが帰って来ているのでレスポンスの値に応じた処理ができる

同じことをasync/awaitでやろうとしたらどうなるかやってみる

async/await

async function 宣言は、 AsyncFunction オブジェクトを返す 非同期関数 を定義します。非同期関数は非同期でイベントループを介して実行され、暗黙的にPromiseを返します。

await 式は、async 関数の実行を一時停止し、 Promise の解決を待ちます。そして async 関数の実行を再開し、解決された値を返します。

developer.mozilla.org

多分async/await旨味は、
await式で結果が得られるのを待つという挙動で
これにより同期処理のような記述ができるという点が良いんだと思う

で、さっきのコードをasync/awaitにしてみると

async function asyncCall() {
  try {
    const val = await apiResponse
    if (val.data.pref === '沖縄県') {
      console.log('はいさい')
    } else {
      console.log('うぇい')
    }
  } catch (e) {
    console.log('error:' + e)
  }
}

asyncCall()

console.log(apiResponse)

apiResponseを非同期的に呼ぶために
asyncがついた関数asyncCall を定義した

これはasyncの関数の中でないとawaitが呼べないからと言う理由
(asyncの無名関数にして即時実行もできる)

そしてasyncCall()の中で
const val = await apiResponse とすることで
apiResponseの処理を待って以後の記述の処理が実行される

使い所ってどこだろう

今回の例だと非同期処理が1個なのでわかりにくいかも知れないけど
複数の非同期処理が存在して逐次その結果に応じてその処理が行われるとすると

Promiseだと、以下みたいにネストするんだろうなーみたいなのが想像できて

promise1.then((val1) => {
  promise2.then((val2) => {
    promise3.then((val3) => {
      //.....
    })
  })
})

async/awaitだと、
同じインデントレベルでゴニョゴニョ書くことが出来て見やすいみたいな利点かなー

async function asyncCall() {
  try {
    await promise1
    await promise2
    await promise3
  } catch (e) {
    
  }
}

まとめ

Promiseとasync/awaitの違いってなんだろうと思い調べ始めたけど
実質的には、扱っているものは同じPromiseで、同じインデントレベルで書けるか否かって感じ

結局、非同期処理の定義はPromiseでしなきゃいけないし
複数の非同期処理を実行するときにasync/awaitを使ってねっていう話だった

変に混同して使わないように気をつけたい

github.com

[追記]async/awaitでも起きるthen().then()地獄

2019/03/21追記

仕事でjsを書いていたらこんな事案に出会ったのでメモ

function create() {
  asyncHoge().then((resultHoge) => {
    asyncFuga(resultHoge).then((resultFuga) => {
      return resultFuga
    })
  })
}

async function asyncHoge(param) {
  const hoge1 = await getHoge1(param) 
  return await getHoge2(hoge1)
}

async function asyncFuga(param) {
  const aaaa = await aaaa()
  return aaaa + param
}

まぁ何を言いたいかというと

ということで、Promiseじゃんってなった

asyncなくてもawait書けるようにするProposalが出ているみたいだけど
非同期処理当たり前のサーバサイド脳からすると
全部awaitを書きそうになる危険性が.....

便利そうだけど怖いねって教えてもらった