はじめに
前回の、目指せ!JavaScriptカスタマイズ中級者(1)〜webpack編〜ではWebpackの導入について説明しました。
Webpackを導入することで新しい記述が使えるのは前記事でお伝えしたとおりですが、新しい記述方法の一つである、async/awaitを使うことによって非同期処理を書きやすくしていきたいと思います。
シリーズの記事一覧はこちら。
async/awaitとは
APIにアクセスするときも、普通のコードを書くように、上から下に順次で同期的に実行され、データをとって変数にいれたり処理を待てるよう、async/awaitはそれを実現できる新しい記法です。(実際のサンプルは後述)
async/awaitはPromiseオブジェクトを利用しており、Promise処理が書きやすくなったものと理解して差し支えありません。
ブラウザの対応状況
async/awaitはInternet Explorer 11(IE11)で動作しません。ですが、前回紹介したWebpackを利用してビルドすれば、IE11でも動作します(Polyfillが入るため)。
Webpackなどを使わず単体で使用したい、という場合はIEでは動かないことに留意して使いましょう。
Promiseの問題点
Promiseは下記のようなデメリットがあります。
- Promise以外の通常のコードと比較すると難しい
Promiseに慣れていないと、通常のコードを書くのと比べるとかなり難しく感じてしまいます。理由は、通常のコードは普通に書くだけで上から下に処理が進むのに、Promiseの場合はresolveやthenなどを駆使してうまく数珠つなぎにして書かないといけないことだと思います。 - 連続した非同期処理を書く場合はthen()でつないだりと、さらに複雑になる
※上から下に順次で同期的にコードが実行されないのは、APIに通信する際など非同期処理が行われる場合です。JavaScriptの制約上、レスポンスが返ってくるまでそのまま待つということができません。(やろうとするとブラウザ自体をフリーズさせてしまうため)
下記はPromiseを使って3回直列で他のレコードを取得する場合の例です。
async/awaitの利点
async/awaitを使うと、下記のようなメリットがあります。
- 非同期処理にPromiseを使うのを比べて簡潔で直感的にかけるようになる
- 連続した非同期処理を書く場合でも、then()でつなげて書く必要がない
- Promise利用時と同じくPromiseオブジェクトを扱うことになるため.then()や.all()などのPromise関数も合わせて使える
通常のPromiseを使ったものと比較してみます。
- 通常のPromiseでレコード詳細画面を開いたときに他のレコードを取得する
- async/awaitを使ってレコード詳細画面を開いたときに他のレコードを取得する
このように書くだけで、通常の変数宣言のように、resp変数にAPIから取得したResponseを格納することができます。
ルールとしては、awaitを使う場合は、その関数の先頭にasyncを付け、async関数であることを示す必要があります。
async関数はPromiseを返却します。そのため、kintone側も結果を待つことができています。
async/awaitの使い方
このように、関数の頭に async を宣言し、待ちたい処理の箇所に await を宣言します。asyncをつけ忘れることも多いので気をつけてください。実際のkintoneでの使い方は詳細は具体例で示します。
MDNにも例がありますので必要に応じて参照ください。
具体例
その他具体的な例も見ていきましょう。比較のために通常のPromiseで書いたものと、async/awaitで書いたものを示します。
例1 レコード編集時に別レコードから取得したデータを使ってデフォルト値を設定する
- Promiseを使った例
- async/awaitを使った例
※エラー制御はtry/catch構文を使うことができるようになります。
kintone.apiからどのようなエラーが返却されるかは下記リファレンスを参考ください。
https://developer.cybozu.io/hc/ja/articles/201941754#step10
例2 レコード保存時に3つのレコードを取得し、合算する
- Promiseを使った例
- async/awaitを使った例
このように特に数珠つなぎで書く場合、非常に見通しがよくなりますね。
Promiseを考慮する(Promiseは不要ということではない)
async/awaitを使えば一切Promiseについて知らなくてもいいかというとそういうことではなく、前述のとおり非同期処理を書きやすくなっただけですので、Promiseの概念自体は知っている必要があります(Promiseも使えるとベター)。
Promiseとasync/awaitには次のような関係性があります。
- awaitを使ってPromiseの処理が終わるのを待つことができる
すでに例で示してあるとおり、kintone.api()をawaitで待つ事ができます。それはkintone.api()はPromiseオブジェクトを返却しているためです。 - async関数はPromiseを返却する
async関数はPromiseオブジェクトを返却します。そのため上記のようにthenとawaitを両方使い合わせることができます。
ただし、混乱の元になりますので極端に書き方を混在させるようなことはしないほうがいいでしょう。
さいごに
2020年1月のアップデートで、フィールド変更時イベントを除く全てのイベントがPromiseをサポートしました。それまでは表示系のイベントなどはPromiseをサポートしておらず、非同期処理がPromiseで表現できませんでしたが、気軽にPromiseを使えるようになりました。Promiseが使えるということはもちろんasync/awaitも利用できますので、他アプリのデータ取得など、非同期処理を使いこなしていきましょう。
PromiseはJavaScriptや非同期処理に慣れていないと難しい概念です。async/awaitを利用しても、実際にはPromiseを操作することには代わりありませんが、コードの見通しが直感的になります。最初はわからないこともあると思いますが、繰り返し使えば少しずつ分かってくるようになります。なれていきましょう。
シリーズの記事一覧はこちら。
このTipsは、2020年4月版 kintoneで確認したものになります。
「Promiseを考慮する(Promiseは不要ということではない)」の内容が、一部、順番が前後している気がします。例えば、最後の行で「下記のように」とありますが、最後の行なので「下記」に該当するところは無く、本当は、少し上のコードを指しているように思います。そして、その後に「ただし、混乱の元になりますので・・・」の文が来るのかなと感じました。
Toshi Akazawa 様
お世話になっております。
cybozu developer network 運営でございます。
記事へのフィードバックありがとうございます。
ご指摘の通り文章が一部誤っていたため、修正いたしました。
以上、よろしくお願いいたします。
"例1 レコード編集時に別レコードから取得したデータを使ってデフォルト値を設定する"の”async/awaitを使った例”ですが、
最後に ")" が抜けているようです。
mikan 様
お世話になっております。
cybozu developer network 運営でございます。
記事へのフィードバックありがとうございます。
ご指摘の通りコードが一部誤っていたため、修正いたしました。
以上、よろしくお願いいたします。