🚴
ジェネレータが便利な理由:無限スクロールを例に学ぼう
広辞苑のように、机の上にただ置いてあった『JavaScript 第7版』。
久しぶりにちょと見てみようかなー、なんて気分で目次をパラパラ眺めていると…目に留まったのが 「ジェネレータ」。
存在は知っていたけど、いまいち理解していないなあというところで、AIのサポートのもと調べてみることに。
そして気づいてしまったのです。
ジェネレータって、めちゃくちゃ便利じゃないか!
というわけで、 その魅力と、「ジェネレータ」 を使った、スマホやパソコンでよく見る 無限スクロール を作る方法をわかりやすく説明します!
1. ジェネレータって何?
ジェネレータは 「一度に全部動かない関数」 です。普通の関数は、呼び出すと全部一気に終わりますが、ジェネレータは途中で止まったり、続きを動かしたりできます。
ジェネレータの特徴
-
function*
を使う- ジェネレータ関数は
function
の後に*
を付けて書きます。 - これが「普通の関数」と「ジェネレータ関数」を区別するポイントです。
- ジェネレータ関数は
-
yield
キーワードでデータを返す-
return
ではなくyield
を使います。 -
yield
は「データを返して一時停止」する役割があります。
-
-
.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. 無限スクロールを作る流れ
- 画面を下にスクロールしたら、新しいデータを取りに行く。
- データが返ってきたら、それを画面に追加する。
- この動きを何度も繰り返す。
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」のデータを表示する。
- ユーザーが画面を下に動かすと「ページ2」のデータを取りに行く。
- これを繰り返して、ずっとデータを追加していく。
8. まとめ
無限スクロールはよく使う便利な機能です。ジェネレータを使うと、データを一度に全部取らず、少しずつ処理できるので、コードがスッキリ書けます。
このの解説をもとに、ぜひ自分のプロジェクトにジェネレータの実装やそれを使った無限スクロール機能を取り入れてみてください!
Discussion