技術系

それ非同期じゃなくていいよね?

技術系

こんにちは、なかにしです。

最近は本業も忙しいのですが、
引っ越しをしたのでさらに忙しくなっています。

引っ越し業者は高いですし、
気分転換も兼ねて家具を一新することにしたので、
最終的に段ボール10個くらいに収まりました。やったね。

今回は非同期処理についてです。

現在はReactでフロント部分を書いているのですが、
コードレビューする時にこれはもったいないと思った点があったので共有です。

いってみよう!

コード概要

ざっくりそのコードを再現します。

  const fetchData = async () => {
     // データを取得して返す処理
  };

  const fetchData2 = async () => {
    // データを取得して返す処理
  };

  const fetchData3 = async () => {
    // データを取得して返す処理
  };  

  const getUserData = async () => {
    // データ取得
    const responseData = await fetchData();
    const responseData2 = await fetchData2();
    const responseData3 = await fetchData3();

    // responseData, responseData2, responseData3を使用した処理
  };

3カ所からデータを取得するようなコードです。
これの勿体ないところは、「3カ所が各々、非同期になっている所」です。

確かにデータ取得後、そのデータを使用した処理が続いているので、awaitで待つのは正しいのですが、1カ所ずつ実行結果を待つ必要はありません。3カ所の結果が返ってくるのを待てば良いのです。

つまり、「1カ所データ取得×3」ではなく、
「3カ所データ取得×1」にしましょうという話です。

以下が修正後のコードになります。

  const fetchData = async () => {
     // データを取得して返す処理
  };

  const fetchData2 = async () => {
    // データを取得して返す処理
  };

  const fetchData3 = async () => {
    // データを取得して返す処理
  };

  const getUserData = async () => {
    // データ取得
    const [responseData, responseData2, responseData3] = await Promise.all({fetchData(), fetchData2(), fetchData3() });

    // responseData, responseData2, responseData3を使用した処理
  };

これで、3つのデータ取得は同期で動き、無駄がなくなりました。
念の為、時間を計測してパフォーマンスの違いを確認してみましょう。

ほんとにパフォーマンス上がるの?

計測して確認します。
データ取得はダミーデータでおなじみ、json placeholder を使用します。

※計測ごとに履歴やキャッシュは削除し、同じ条件下で計測しています。

以下、コードです。

await 3連発

import "./App.css";

function App() {
  const fetchData = async () => {
    const responseData = await fetch(
      "https://jsonplaceholder.typicode.com/posts"
    );
    const responseDataJson = await responseData.json();

    return responseDataJson;
  };

  const fetchData2 = async () => {
    const responseData = await fetch(
      "https://jsonplaceholder.typicode.com/comments"
    );
    const responseDataJson = await responseData.json();

    return responseDataJson;
  };

  const fetchData3 = async () => {
    const responseData = await fetch(
      "https://jsonplaceholder.typicode.com/albums"
    );
    const responseDataJson = await responseData.json();

    return responseDataJson;
  };

  const getUserData = async () => {
    // 計測開始
    const startTime = Date.now();

    // データ取得
    const responseData = await fetchData();
    const responseData2 = await fetchData2();
    const responseData3 = await fetchData3();

    // データ表示
    console.log(responseData);
    console.log(responseData2);
    console.log(responseData3);

    // 計測終了
    const endTime = Date.now();
    const time = endTime - startTime;
    console.log(`${time}ms`);
  };

  return (
    <div className="App">
      <button onClick={getUserData}>ボタン</button>
    </div>
  );
}

export default App;

計測結果

・Edge
初回→ 219 ms
2回目→ 64 ms
3回目→ 49 ms

・Chrome
初回→ 223 ms
2回目→ 82 ms
3回目→ 89 ms

もちろん、ちゃんとデータも取れています。

Promise.allで同期処理

計測結果

・Edge
初回→ 120 ms
2回目→ 26 ms
3回目→ 25 ms

・Chrome
初回→ 197 ms
2回目→ 30 ms
3回目→ 28 ms

もちろん、データも取れています。

まとめ

ブラウザ/対象await 3連発Promise.allで同期処理
Edge 1回目219120
Edge 2回目6426
Edge 3回目4925
Chrome 1回目223197
Chrome 2回目8230
Chrome 3回目8928

どのブラウザでも、何回目であっても同期処理の全勝でした。

今回は100個ほどのデータでしたが、
10000個くらいになると秒単位でかわってくるんじゃないかなーと思います。

フロントは早さが正義なので、
非同期処理を使う際は、ぜひこの記事を思い出してくださいね!

今回はここまで!
Enjoy Hacking!