一覧データを表示したり、さらにそこから関連データを表示する際など、ループ処理(繰り返し処理)の中でネットワーク処理を行うことはよくあります。しかし、各ネットワーク処理が1秒で終わるとしても、10回ループすると10秒かかってしまいます。そうした処理の累積時間はユーザにとってはストレスで、アプリ離れを引き起こします。
今回はネットワーク処理が伴うループ処理を高速化する方法と、実際の測定結果を紹介します。
処理の書き方は3つ
ネットワーク処理を伴うループの書き方は全部で3つあります。
- async/awaitを使う
- Promiseを使う
- Promise.allを使う
これらを上から順番に紹介します。今回はJavaScript SDKを使いますが、他のプログラミング言語でもasync/awaitが一般的になってきているので、それほど変わらないはずです。
async/awaitを使う
サンプルのコードです。1〜3は実行される順番です。ループ処理が終わるまでは3が実行されないので、async/awaitは分かりやすいコードが書けます。
const start = new Date const photos = await Photo.fetchAll() // 1 for (let photo of photos) { const data = await ncmb.File.download(photo.get('fileName'), 'blob') console.log(data) // 2 } // 3 const end = new Date console.log(end.getTime() - start.getTime())
この場合の処理時間(データは4件)は7.156sでした。
Promiseを使う
サンプルのコードです。ネットワーク処理は非同期なので、ループ内の処理が完了する前にforを抜けてしまいます。この点がasync/awaitとの違いになります。全件処理したかどうかが分からないので、処理件数のカウントを取っておき、その数をもって全件処理済みかどうかを判断しています。
const start = new Date const photos = await Photo.fetchAll() let count = 0 // 1 for (let photo of photos) { ncmb.File.download(photo.get('fileName'), 'blob') .then(blob => { // 3 count++ console.log(photo.get('fileName'), blob.length) if (count === photos.length) { const end = new Date console.log(end.getTime() - start.getTime()) } }) } // 2
この処理の場合、3.476sでした。データ数や転送量によりますが、処理がasync/awaitの場合に比べて2倍以上高速化しています。
Promise.allを使う
サンプルのコードです。ファイルダウンロード処理をPromise.allでまとめて処理しています。その結果、ダウンロード処理の並列化と、その後のforループ処理の同期化が実現できます。Promiseを使った時にはforループをその中の処理が終わる前に抜けてしまっていましたが、この場合はすべての処理が終わってから行われるようになります。
const start = new Date const photos = await Photo.fetchAll() // 1 const data = await Promise.all( photos.map(photo => ncmb.File.download(photo.get('fileName'), 'blob')) ) // 2 for (let index in data) { // 3 const photo = photos[index] const file = data[index] console.log(photo.get('fileName'), file.length) } // 4 const end = new Date console.log(end.getTime() - start.getTime())
この処理の場合、時間は3.726sでした。処理としてはPromiseを単純に使った場合と同じなので、0.3sは誤差といえるでしょう。
まとめ
ネットワーク処理は何度も行うと時間がかかってしまいます。なるべくデータを一回で取れるようにしたり、処理を並列化する工夫が必要です。今回のように簡単なコードでも2倍以上高速化されます。アプリ開発の際にはこうした点に注意して実装してください。