【React Native】asyncとawaitってなに?
現在作成中のアプリの方で、ローカルストレージに値を入れてその値を取り出して使う機能を搭載しなければならなくなり、AsyncStorageを使用することになりました。
公式ドキュメントを見ればわかる通り、AsyncStorageはキーと値を簡単に保存・取得できる初心者でも扱いやすいストレージです。
ところが、僕はAsyncStorageを使っているうちにある疑問にぶつかりました。
asyncとawaitってなに…?
そう、値を保存するときも取得するときも「async」とか「await」とかいう謎の単語が出てくるのです。
最初、これ別に必要ないんじゃね…?と思って消してコードを書いてたりしたんですがうまくいかず、機能実装にかなり悩んでいたところ先輩が超絶優しくわかりやすく教えてくれました。ここでは僕の拙い文章ですが自分の備忘録として、またReact Native始めたばかりの人にあてて同期・非同期処理の概要について記そうと思います。
正直、ここで話すことは本当にさらっと表面を撫でるだけのなんの生産性もない記事だと思うので、もっと詳しくためになる記事を以下に貼らせていただきます。
ここからかなり勉強させていただいたこともあるので、それも踏まえながら自分的にまとめていこうと思います。
また、自分の経験上AsyncStorageを使っている時に当たった問題だったので、関数もAsyncStorage内にあるものを例にあげて使用します。
async/awaitとは?
async/awaitは、JavaScriptで非同期処理を扱う新しい方法です。
ここで同期処理と非同期処理の違いを確認しましょう。
同期処理とは…プログラムの上から順に実行していく方式のこと。もし時間のかかるプログラムがあったとしても、そのプログラムが終了するまでは次のプログラムは実行されない。
非同期処理とは…もし実行中のプログラムがあったとしても、他のタスクが別のプログラムを動かせる方式。
だから、AsyncStorageにおけるasync/awaitは、ストレージから値を取り出している最中でも他のプログラムが動かせるようになっているということ。
今回、僕が作っているアプリはネットに繋がなくても使用できるように作られているアプリだったのであまりasync/awaitの恩恵は受けられませんでしたが、これらはネットに繋げた時に効果を発揮します。
ネット上にストレージがあってその値を取り出す場合、回線の速度によっては時間のかかる場合があります。そこで毎回終了するまで待つということは、他の操作ができなくなるということです。それはアプリとしてよろしくない。そんな解釈です。
どういう動きをしてるのか
上の図はプログラムの流れを描いています。1=>2=>3=>4=>とプログラムが処理されていって、5番でgetItem()という関数が呼ばれます。この関数はAsyncStorageでは引数に入っているキーと合致する値を持ってくるものなのですが、ここで同期処理の場合一旦本筋の処理はストップして(点線部分にはいかない)分岐して6=>7=>...とgetItem()内の処理が実行されることになります。
なので、同期処理で書いていった場合はまたgetItem()の中で時間のかかる関数が呼び出された場合はまた右に分岐して、またさらに分岐して、…と複雑になってしまいます。
そこで登場するのがasync/awaitの非同期処理です。async/awaitは動きは同期処理っぽいのに非同期処理をやってくれるというもので、
やっていることは実質的に同じなのですが、見かけ上プログラムの流れを一本の道にしてくれます(図でいう5=>6の段差がないように「見せかけてくれる」ということ)
async/awaitが登場する前、コールバック関数という.then().then()...とバカみたいに関数を繋げていたころからはるかに見やすく書きやすくなりました。
asyncの役割
async/awaitと合わせて呼んでいましたが、それぞれ別のものです。
asyncはfunctionの前に書くキーワードで、AsyncFunctionを作成することができます。
AsyncFunctionでは、awaitを使うことができます。awaitはAsyncFunctionの外では使うとエラーになります(経験済み)。
awaitの役割
awaitはAsyncFunctionの中で動作し、その後に書かれた処理が終了するまでAsyncFunction内の処理をそこで一時停止します。
処理が終了すると次のプログラムが実行されます。
なので、asyncとawaitはセットとして考えればわかりやすいと思います。
AsyncStorageを使うときの注意
僕的にAsyncStorageを使う時にハァ?となった部分をおさらいします。
Promiseオブジェクト
Promiseオブジェクトってなに…?async/awaitでもう頭の中いっぱいいっぱいなのになんでこんなん出てくるねん…って思っていたのですが、これも結構重要です。
Promiseオブジェクトは非同期処理の最終的な完了処理(もしくは失敗)およびその結果の値を表現します。
非同期処理では、処理をしている途中でも次のプログラムが実行でき、その中に処理中のプログラムの値が必要な場合があります。そんなときにPromiseオブジェクトが見せかけの値としてふるまうということです。
僕はここから単純に値を取り出したかったので、
const temp = await AsyncStorage.getItem(~~~);
ってするわけですよ。
そのあとよし、取り出せたな〜と思って return temp
とかで返して、その値をアプリ内で表示させようとするんですけどエラーが出るんです。
それはPromiseオブジェクトをtempの中に入れているから起きるエラーで、ここは setState
をしなければなりません。
この記事が僕のぶつかっていた問題そのものの質問でした。
非同期処理って難しい?
最初は非同期処理って聞いては?ってなってたんですが、先輩から説明してもらって、今この記事を書いてなんとなくつかむことができました。この記事を見てくれた人の少しでも助けになれれば嬉しいです。
やっぱりプログラミングをやっている途中でぶつかる問題は割と英語のページでヒットすることが多いですね。英語をもっと勉強したいと思いました。
いろいろ難しいですが、調べていてとても楽しかったです。やっぱりプログラミングはおもしれぇなぁ。