# ポーリングをリアルタイム更新に置き換える

> 数秒ごとに API へ問い合わせるのをやめ、変化を一度だけ送ります。リクエストとサーバー負荷を減らし、変化はその瞬間に表示されます。

Source: https://hibira.io/ja/use-cases/replace-polling

多くのアプリは「問い合わせ」で変化を知ります。開いているページが数秒ごとに API を呼び、注文やチケット、レポートが変わったかを確かめるのです。答えはほとんど「変化なし」なのに、そのたびにリクエスト、データベースのクエリ、ユーザーのスマートフォンのバッテリーを使い、実際の変化も次の間隔まで画面に出ません。Hibira なら、変化が起きたときにサーバーが一度だけ送り、そのデータを表示しているすべてのページが数ミリ秒で更新されます。

## ユーザーが得るもの

- 最大 5 秒待つことなく、変化が起きた瞬間に画面に表示。
- 再読み込みなしで、どのタブも常に最新。
- スマートフォンが数秒ごとに無駄に通信しなくなる。

## ポーリングのコスト

1,000 人がページを開いたまま 5 秒ごとにポーリングすると、1 時間で 720,000 リクエストになります。その 1 時間にデータが 200 回しか変わらなければ、99.97% のリクエストは新しい内容を返しません。プッシュなら同じ 1 時間は 200 メッセージで済み、API が処理するのは各ページの最初の読み込みだけです。

## 使う機能

- **プライベートチャンネル**（`private-order-42`）。ページに表示するものごとに 1 つ用意し、サーバーが認可するので、ユーザーには自分のデータだけが届きます。
- 公式サーバー SDK の **`trigger`**。変更を保存した直後に呼びます。
- **`pusher:subscription_succeeded`**。最初の接続時と再接続のたびに発火するので、現在の状態を読み込むタイミングに最適です。

```text
flow: ポーリングは何度も問い合わせ、プッシュは変化ごとに一度だけ送る
== ポーリング
開いているすべてのページ|5 秒ごと --GET /api/orders/42--> API|ほとんど「変化なし」
== プッシュ
API|変更を保存 --`trigger()` を一度--> *Hibira --WebSocket--> 表示しているすべてのページ|すぐに更新
```

## ステップ 1：ポーリングのループを見つける

たいていこのような形です：

```js
setInterval(async () => {
  render(await fetch('/api/orders/42').then((r) => r.json()));
}, 5000);
```

## ステップ 2：一度読み込み、あとは待ち受ける

[JavaScript ガイド](https://hibira.io/ja/guides/javascript)のとおりに接続し、プライベートチャンネル用の認可エンドポイントを用意します。購読の準備ができたら現在の状態を読み込み、その後は変化が届くたびに反映します：

```js
const load = async () => render(await fetch('/api/orders/42').then((r) => r.json()));

const channel = pusher.subscribe('private-order-42');
channel.bind('pusher:subscription_succeeded', load);
channel.bind('updated', (order) => render(order));
```

## ステップ 3：保存したときに変化を送る

データが変わる場所（API ルート、ワーカー、管理画面の操作、Webhook）で、書き込みが成功したあとに配信します：

```js
app.patch('/api/orders/:id', requireLogin, async (req, res) => {
  const order = await db.orders.update(req.params.id, req.body);
  await pusher.trigger(`private-order-${order.id}`, 'updated', order);
  res.json(order);
});
```

## ステップ 4：軽い保険を残す

再接続後に購読がもう一度発火するので、接続が切れていた間の抜けは `load()` が埋めてくれます。ブラウザーはバックグラウンドのタブを凍結することもあるため、タブが前面に戻ったときにも一度読み込みます：

```js
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'visible') load();
});
```

## ヒント

- 再描画に必要な内容を送ります。大きなデータは ID とバージョンだけ送り、残りはページに取得させます。
- 同じデータが毎秒何度も変わる場合は、[リアルタイムダッシュボード](https://hibira.io/ja/use-cases/live-dashboards)のようにまとめて送ります。
- 頻繁に変わる一覧は、行ごとではなく一覧ごとに 1 チャンネル（`private-orders-team-7`）にできます。
- イベントのサイズはプランによって異なります。[料金](https://hibira.io/ja/pricing)をご覧ください。
- 配信前に何人が見ているか知りたい場合は、[オンライン人数](https://hibira.io/ja/use-cases/online-user-counts)をご覧ください。
