【JavaScript】Promiseとasync/awaitの備忘録(JSの非同期処理を操るために)

投稿日:

プログラミング初心者の勉強ブログ #128

JSのPromise(async/await)のイメージを記事書きながら復習する。JSで色々やり始めると、関数の処理順が自分の意図した順番でなくなることが多くあり、それはつまりJSの非同期で処理される関数を自分で操れていないから生じるエラーである。JSの伸び代はいかに非同期を使いこなせるかみたいな部分にあるんじゃないかと思った。

 

目次

 

きっかけはGoogle MAPs API

今回のチーム開発では飲食店のフードロスを課題とし、BtoCだけでなくCtoCも視野に入れた、作りすぎた料理をユーザー間で売買できるサービスのアプリを開発していた。

map

Google Map はこのようにuser情報をマップに表示するために利用しており、ユーザーが投稿した料理は、

 

投稿

 

現在位置と投稿された料理(投稿ユーザーの登録住所)の距離をAPIで算出し、近い順に並べ替えている。

 

この機能の流れを書き起こすと、

  1. httpリクエストでurlが叩かれる
  2. ユーザー情報と料理情報をDBから取得
  3. いったん、httpレスポンスで料理情報を料理一覧としてHTMLでレンダリング(距離によるsortなし)
  4. 現在位置を取得
  5. ユーザー情報と現在位置を元にMAP APIでマップを表示
  6. 料理の位置情報と現在位置を元にMAP APIで距離と時間を取得
  7. 距離順で料理をソートして料理一覧を上書きレンダリング
  8. 各料理に距離と時間をレンダリング

ざっくりとこんな感じになった。現在位置取得やaxiosでの裏のPHPとの通信(sortなどをPHPで行ったため)が非同期であり、それらの実行結果を元にMAP APIと通信し連携させるため、非同期がいろいろと思わぬ挙動をした。

 

Promise

promiseのイメージ

Promiseを理解するにはまず、「同期」と「非同期」を明確に理解しないといけない。通常のプログラムは同期で実行される。要は上から下へ書いた順に実行される。順次処理が行われること、これが同期である。

一方で、プログラムに非同期で実行される関数が含まれる場合、上から下へ書いた順に実行されるとは限らない。JSはここがおもしろポイントだと思う。

洗濯して干してアイロンをかける場合、全て同期なら

  • 洗濯
  • 干す
  • アイロン

と上から下へ順番に書いておけば、シワのないTシャツを着ることができる。

しかし、もし「洗濯」が非同期であった場合、

「干す→アイロン→洗濯」

みたいな実行順序になってしまう可能性がでる。びしょびしょのTシャツを着ることになってしまう。これがプログラムの場合は当然エラーが出る。

 

非同期はとはこういうことであり、PromiseはびしょびしょのTシャツを着ることのないように非同期を操作するために用いる。

 

promiseは自分で終わらせる

promiseは状態(ステータス)を3つ持つ。

  1. 実行中
  2. 実行完了(正常)
  3. 異常事態

プロミスは「new Promise」でインスタンスとして生成でき、初期状態は1の実行中である。プロミスの書き方は色々なサイトで書いてあるので割愛するが、要はPromiseには3つの状態のうちどれか1つを持たせることができ、promiseの状態が変化したタイミングをイベントハンドラー的な感じで取得できる。これを利用することで、非同期処理の順番を操作できる。

promiseインスタンス内に非同期関数を入れ込み、それらすべてが実行完了したタイミングでそのpromiseの状態を「resolve()」で1から2へ変化させる。その変化をトリガーに「.then()」内に記述したコードが実行される。エラー時は「reject()」して1から3へ状態を変え、「.catch()」に回す。

Promiseは自分で作成する場合、必ず状態を変えなければならない。そうしないとthenやcatchが動かない。

 

async/await

async/awaitはpromiseを書きやすくしたもの。promiseを知らなきゃpromiseを書きやすくしたものとか言われてもわからない。

 

promiseの状態をreturn時に変えてくれる

「async function」で非同期関数を定義でき、返り値がpromiseとなる。returnでresolve、throwでrejectと同様の挙動となり、promiseを状態変化させた形で返り値をつくる。単純にasync functionを定義し、returnで返せばそれがpromiseとなるので書きやすい。

一方awaitは、後ろにpromiseを置くことで、そのpromiseが状態2か3になるまで、await以下に書いた処理を待つ。つまり、awaitを使えばpromiseを同期処理のように書ける。

 

参考:async/await 入門(JavaScript) - Qiita

 

awaitはasync関数内でのみ使える

awaitはasync関数内でのみ呼び出すことができる。なのでasyncとawaitはセットで覚える。というよりセットでないと覚えられない。非同期のコーディングはなんとも言えない言葉では説明しづらい難しさがあると思う。

 

正直まだまだよくわかってない

基本的な挙動の理解までで、例外処理の対応あたりがまだQiita読んでてもしっくりきていない。誰か教えて欲しい。

 

まとめ

JSもっと書けるようになりたいです。

以上ありがとうございました。

 

 

 

 

 

 

 

-プログラミング学習
-, ,

Copyright© s u p ? , 2019 All Rights Reserved.