🚴

ジェネレータが便利な理由:無限スクロールを例に学ぼう

に公開

広辞苑のように、机の上にただ置いてあった『JavaScript 第7版』。
久しぶりにちょと見てみようかなー、なんて気分で目次をパラパラ眺めていると…目に留まったのが 「ジェネレータ」

存在は知っていたけど、いまいち理解していないなあというところで、AIのサポートのもと調べてみることに。

そして気づいてしまったのです。
ジェネレータって、めちゃくちゃ便利じゃないか!

というわけで、 その魅力と、「ジェネレータ」 を使った、スマホやパソコンでよく見る 無限スクロール を作る方法をわかりやすく説明します!

1. ジェネレータって何?

ジェネレータは 「一度に全部動かない関数」 です。普通の関数は、呼び出すと全部一気に終わりますが、ジェネレータは途中で止まったり、続きを動かしたりできます。

ジェネレータの特徴

  1. function* を使う

    • ジェネレータ関数は function の後に * を付けて書きます。
    • これが「普通の関数」と「ジェネレータ関数」を区別するポイントです。
  2. yield キーワードでデータを返す

    • return ではなく yield を使います。
    • yield は「データを返して一時停止」する役割があります。
  3. .next() メソッドで次のデータを取得

    • ジェネレータを実行すると イテレーターオブジェクト が返ってきます。
    • .next() を呼び出すたびに、yield のところまで処理が進みます。

ジェネレータの例

function* myGenerator() {
  yield "りんご"; // ここで一旦止まる
  yield "みかん"; // 次にここまで動く
  yield "ぶどう"; // さらに次にここまで動く
}

const fruits = myGenerator();

console.log(fruits.next().value); // りんご
console.log(fruits.next().value); // みかん
console.log(fruits.next().value); // ぶどう

2. ジェネレータを使うメリット

無限スクロールだけでなくジェネレータは色々なケースでの活用が可能です。
下記のポイントを活かせば、ジェネレータのメリットを実感しながら効率的でメンテナブルなコードを書けるようになります。

1. 効率的

  • 必要なデータだけを「その時に応じて」取得するので、大量のデータを一度に扱わずに済む。
    • : 無限スクロールで、画面に表示されないデータを事前に全て取得すると、メモリやネットワークが無駄になるが、ジェネレータなら次のデータだけを効率よく取得できる。

2. 非同期処理に最適

  • ジェネレータは yield を使って途中で処理を一時停止し、非同期処理の完了を待つようなフローを簡潔に書ける。
    • : APIリクエストでサーバーからデータを取得する処理を待ちながら、次のリクエスト準備を整えられる。

3. シンプルに状態を管理

  • 状態(例えば、現在のページ番号や取得データ数)をジェネレータ内で保持できるため、外部で別に管理する必要がない。
    • : 無限スクロールで「次に取得するデータのページ」をジェネレータ内で記録し、関数外で管理する手間を省ける。

4. コードの見通しが良くなる

  • データ取得や状態管理の流れを 逐次処理的に書ける ため、コードが読みやすくなる。
    • : 複雑な非同期ロジックや条件分岐をコールバック地獄にせず、一行ずつ順番に記述できる。

5. 柔軟なデータストリーム処理

  • データをひとつずつ返せるため、途中で処理をカスタマイズするのが簡単
    • : 無限スクロール中に特定の条件(例: フィルタリングやエラー発生)で処理を中断したり、別のデータを差し込むことも可能。

6. パフォーマンスの向上

  • 一度に大量のデータをメモリに保持しないため、メモリ効率が良く、特に大規模データを扱うアプリケーションでパフォーマンスが向上する。
    • : 10万件以上のデータを扱うアプリで、必要なデータだけを随時取得して画面に反映する。

4. 無限スクロールとは

ようやく本題の無限スクロールです。
無限スクロールは、画面を下にスクロールすると、新しいデータがどんどん出てくる仕組みです。

例えば、InstagramやTwitterで画面を下に動かしていくとどんどん新しい投稿が出てくる、あれが 無限スクロール です。

5. 無限スクロールを作る流れ

  1. 画面を下にスクロールしたら、新しいデータを取りに行く。
  2. データが返ってきたら、それを画面に追加する。
  3. この動きを何度も繰り返す。

6. 実際に作ってみる

HTML(画面の枠)

<div id="content"></div>
<div id="loading">読み込み中...</div>

CSS(デザインの設定)

#content {
  font-size: 18px;
  line-height: 1.5;
}
#loading {
  text-align: center;
  font-size: 18px;
  margin: 20px 0;
}

JavaScript(ジェネレータを使った無限スクロール)

// データをもらうジェネレータ
async function* fetchData() {
  let page = 1;
  while (true) {
    console.log(`ページ ${page} のデータを取りに行きます!`);
    const response = await fetch(`https://example.com/api?page=${page}`);
    const data = await response.json();
    yield data; // ここでデータを返して、一旦止まる
    page++;
  }
}

// ジェネレータの用意
const generator = fetchData();
const content = document.getElementById("content");
const loading = document.getElementById("loading");

// データを画面に追加する関数
async function loadMoreData() {
  loading.style.display = "block";
  const { value: data } = await generator.next();
  loading.style.display = "none";

  data.forEach((item) => {
    const div = document.createElement("div");
    div.textContent = item.name; // データの名前を画面に追加
    content.appendChild(div);
  });
}

// スクロールを監視する
window.addEventListener("scroll", () => {
  if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
    loadMoreData(); // 下まで来たらデータを読み込む
  }
});

// 最初のデータを表示
loadMoreData();

7. どんな感じで動くのか?

  1. 最初に「ページ1」のデータを表示する。
  2. ユーザーが画面を下に動かすと「ページ2」のデータを取りに行く。
  3. これを繰り返して、ずっとデータを追加していく。

8. まとめ

無限スクロールはよく使う便利な機能です。ジェネレータを使うと、データを一度に全部取らず、少しずつ処理できるので、コードがスッキリ書けます。

このの解説をもとに、ぜひ自分のプロジェクトにジェネレータの実装やそれを使った無限スクロール機能を取り入れてみてください!

Discussion