【デイトラ学習記録】DAY 17 JavaScriptの非同期通信 – フロントエンド開発編

今回はJavaScriptの非同期通信について学習していきます。

非同期処理と同期処理とは?

同期処理の例

JavaScript
/**
 * 同期処理の例
 * 上から順番に処理される
 */

const syncFunction = () => {
  console.log("Sync function1");
  console.log("Sync function2");
  console.log("Sync function3");
};

syncFunction();
// Sync function1
// Sync function2
// Sync function3

非同期処理の例

  1. 非同期処理とは、すぐに結果を返さず遅れて結果が返ってくる可能性がある操作のこと
  2. 待ち時間で他の処理を行うことも可能で、全体のパフォーマンスがあがる
JavaScript
/**
 * 非同期処理の例
 * setTimeout関数によって、特定の処理を遅らせる
 */
const asyncFunction = () => {
  setTimeout(() => {
    console.log("function1");
  }, 1000);
  console.log("function2");
  console.log("function3");
};

asyncFunction();
// Sync function2
// Sync function3
// Sync function1

fetchの概念

フェッチAPIの概念

{JSON} Placeholderを使って、ダミーデータの取得を行います。

APIとは(フロントエンド開発の中で使用される文脈だと)サーバーへリクエストを投げると、JSON形式で何かしらのデータを返してくれるもの

fetch → JavaScriptの組み込み関数。APIを叩いてデータを取得するために組み込み関数

JavaScript
fetch("https://jsonplaceholder.typicode.com/users")
  .then((response) => response.json())
  .then((json) => console.log(json));
  .catch((error) => console.error("Error", error));

[検証ツール] → [Network] → [Fetch/XHR] のタブから、リクエストを投げて返ってきたデータを確認できます。

Web制作だと、まず見ることはないデータですよね…
WordPressの場合にも、裏側ではきっと似たようなことが起きているのでしょうが、詳しく知らなくてもなんとかなります…

fetchを使う場合には、Promiseの概念を理解しておく。

  • fetch関数はPromiseを返し、非同期処理の結果を待つことができます。
  • thenメソッドとcatchメソッドを使って、成功時と失敗時の処理を定義します。
  • このように、fetch関数を使うことで、非同期のネットワークリクエストを簡潔に扱うことができます。

したがって、fetch関数を使うときには、内部的にPromiseが使われているため、Promiseの概念を理解していると、非同期処理をより効果的に扱うことができます。

JavaScript
/**
 * Promiseを使った非同期処理の例
 */
const promiseTstFunction = () => {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = true;
      if (success) {
        resolve("成功");
      } else {
        reject("失敗");
      }
    }, 1000);
  });

  return promise;
};

promiseTstFunction()
  .then((data) => console.log(data))
  .catch((error) => console.error("Error", error));

処理の流れ

  1. 組み込みクラスPromiseのインスタンスを作る new Promise
  2. インスタンスの引数に関数を持つ
    • new Promiseが成功した場合には、resolveが返る
    • new Promiseが失敗した場合には、rejectが返る
  3. このインスタンスを持つ関数promiseTstFunction() を実行する時、メソッドチェーンで、thencatch が使える
    • promiseTstFunction().then((data) => console.log(data)).catch((error) => console.error("Error", error));

awaitとasyncの概念

組み込み関数の fetch を使用する際に、.then.catch を使う方法を見てきたが、最近だともっと見通しの良い書き方ができる。await を使うことで、以下のようなメリットが得られる

  1. コードが直線的で読みやすい。
  2. 統一的で簡単なエラーハンドリングが可能。
  3. 非同期処理が複数ある場合でもスケーラブル。
  4. 非同期ループや複雑な非同期操作に適している。

そのため、特に複雑な非同期処理を扱う場合や、可読性を重視する場合に await が有効です。

非同期処理をより直感的に扱うための機能
非同期処理を順番に書けるようになる便利な仕組み。

async

asyncは「非同期関数」を作るキーワード。

await

awaitは「非同期処理が終わるまで待つ」キーワード。

JavaScript
const testFunction = () => {
  fetch("https://jsonplaceholder.typicode.com/users")
    .then((response) => response.json())
    .then((json) => console.log(json))
    .catch((error) => console.error("Error", error));
};

await を使うと以下のように書ける

const testFunction = async () => {
  const response = await fetch("https://jsonplaceholder.typicode.com/users");
  if (!response.ok) {
    console.error("Error", error);
  }

  const json = await response.json();
  console.log(json);
};

APIで受け取ったデータをHTMLに表示する

データの受け取り方法について学習してきました。

結局フロントエンドエンジニアは、受け取ったデータをフロントに表示する必要があります。

JSON placeholder で受け取ったテストデータを、HTMLに表示します。

HTML

この中に、APIで取得したデータを追加する

HTML
<table>
  <thead>
    <tr>
      <th class="border p-2">ID</th>
      <th class="border p-2">名前</th>
      <th class="border p-2">電話番号</th>
      <th class="border p-2">メールアドレス</th>
    </tr>
  </thead>
  <tbody id="table-body">
    <!-- ここにAPIで取得したデータが表示されます -->
  </tbody>

JavaScript

APIでデータを取得する

JavaScript
/**
 * @function fetchData - APIデータを取得する関数
 * @returns {Promise<Array>} - ユーザーデータの配列を返す
 * @throws {Error} - データ取得に失敗した場合、エラーをスローする
 */
const fetchData = async () => {
  const response = await fetch("https://jsonplaceholder.typicode.com/users");
  if (!response.ok) {
    throw new Error("データ取得に失敗しました");
  }
  return await response.json();
};

以下のようなデータを10名分受け取れる

JavaScript
[
  {
    "id": 1,
    "name": "Leanne Graham",
    "username": "Bret",
    "email": "Sincere@april.biz",
    "address": {
      "street": "Kulas Light",
      "suite": "Apt. 556",
      "city": "Gwenborough",
      "zipcode": "92998-3874",
      "geo": {
        "lat": "-37.3159",
        "lng": "81.1496"
      }
    },
    "phone": "1-770-736-8031 x56442",
    "website": "hildegard.org",
    "company": {
      "name": "Romaguera-Crona",
      "catchPhrase": "Multi-layered client-server neural-net",
      "bs": "harness real-time e-markets"
    }
  },
  {
    "id": 2,
    "name": "Ervin Howell",
    "username": "Antonette",
    ・・・
    ・・・

受け取ったデータを元にtdタグを生成する処理を追加する

JavaScript
/**
 * @function createTdElement - td要素を生成する関数
 * @param {string} textContent - td要素に設定するテキストコンテンツ
 * @param {Array<string>} classes - td要素に追加するクラスの配列
 * @returns {HTMLElement} - 生成されたtd要素
 */
const createTdElement = (textContent, classes) => {
  const tdElement = document.createElement("td");
  tdElement.textContent = textContent;
  classes.forEach((cls) => tdElement.classList.add(cls));
  return tdElement;
};

/**
 * @function renderTable - 受け取ったJSONを元にDOMを生成する関数
 * @param {Array} usersJsonData - ユーザーデータの配列
 * @returns {void}
 */
const renderTable = (usersJsonData) => {
  usersJsonData.forEach((userData) => {
    // tdタグを生成
    const trElement = document.createElement("tr");
    // tdタグに付与するクラス属性
    const classes = ["border", "p-2"];
    // tdタグに表示するデータのキー
    const keys = ["id", "name", "phone", "email"];

    /**
     * キーを元に。繰り返し処理でtdタグを生成し、trタグに追加
     */
    keys.forEach((key) => {
      const tdElement = createTdElement(userData[key], classes);
      trElement.appendChild(tdElement);
    });

    // 生成したtrタグをtable要素に追加
    const tableElement = document.querySelector("#table-body");
    tableElement.appendChild(trElement);
  });
};

最後に、関数を初期化する

JavaScript
/**
 * @function init - 初期化関数
 */
const init = async () => {
  try {
    const usersJsonData = await fetchData();
    renderTable(usersJsonData);
  } catch (error) {
    console.error("Error", error);
  }
};

init();

APIで取得したデータが表示されました。

完成物

URL

リポジトリ

感想

非同期通信の概念ついて学びました。

APIでデータを受け取って、受け取ったデータを使ってDOMを操作するイメージが掴めました。

  • WPと違いデータを受け取るためのリクエストを送る必要がある
  • 受け取る際に非同期通信を使い、エラーのハンドリングも行う必要がある
  • 受け取れるデータを検証ツールのネットワークタブで確認する必要がある

awaitPromisefetch の概念については、理解半分なので、この辺は数をこなして慣れていく必要がありそうです。

おそらく、APIで取得したデータでDOMを作って、さらにJavaScriptで何かしらのDOMを操作する。
といった作業も考えられます。
その際に、同期・非同期の概念が分かっている必要があるのかと現状は理解してます。(認識合ってるかはまだ自信なしですが・・・)

無料で提供されている、APIが様々あるようなので、何か練習で触って慣れていこうと思います!

Yuta | Code.Yu

WordPressをメインに活動する、フリーランスのWeb制作コーダーです。
React案件を経験したことをきっかけに、さらにフロントエンド開発のスキルを高めるため、JavaScriptやReactの学習を進めています。このブログでは、学習の過程や記録を発信しています。

Web制作に関する情報はこちら
Code.Yu | ホームページ制作・コーディング代行 ↗︎