Promiseしか知らなかったけどasync/awaitを調べて使ってみた
JSの話です
非同期処理苦手だわー(白目) で日頃生きており
やっと最近Promiseが使えるかな(?)になったところ
async/awaitという未知の存在に遭遇したということで
遅いながらも、ちゃんと知っておかなきゃと思い
調査と実際に手を動かしてみたという自分メモの記事です
内容的にはインターネット上でn( n > 10)番煎じ
Promise
Promise オブジェクトは非同期処理の最終的な完了処理(もしくは失敗)およびその結果の値を表現します。
よく使うのは
なんかしら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 関数の実行を再開し、解決された値を返します。
多分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を使ってねっていう話だった
変に混同して使わないように気をつけたい
[追記]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 }
まぁ何を言いたいかというと
昨日async/await書いていて、結局呼び出し側メソッドがasyncでない場合、then()祭りじゃんってなった。promiseと変わらなくね?書き方が悪いのか何なのかわからんけど、このモヤモヤをブログ書いておきたい
— ごま@エンジニアしたいお母さん (@gomaaburamax) March 20, 2019
ということで、Promiseじゃんってなった
async/awaitでも起きるthen().then()地獄に対する解決案。はやく取り込まれて欲しい / 2件のコメント https://t.co/0M74DsVTsR “GitHub - tc39/proposal-top-level-await: top-level `await` proposal for ECMAScript (stage 2)” https://t.co/HCNNdu7Vmw #javascript #ECMAScript
— ごま@エンジニアしたいお母さん (@gomaaburamax) March 20, 2019
asyncなくてもawait書けるようにするProposalが出ているみたいだけど
非同期処理当たり前のサーバサイド脳からすると
全部awaitを書きそうになる危険性が.....
便利そうだけど怖いねって教えてもらった