# 用即時更新取代輪詢

> 別再每隔幾秒就問一次 API：每個變化只送一次，減少請求與伺服器負載，變化一發生就顯示。

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

很多應用是靠「問」來得知變化：每個打開的頁面每隔幾秒就呼叫一次你的 API，看看訂單、工單或報表有沒有變。幾乎每次的答案都是「沒有新的」，但每次都要花一個請求、一次資料庫查詢，還有使用者手機的電量；真的有變化時，也還要等上一個間隔才看得到。用 Hibira，你的伺服器在變化發生時只送一次，所有顯示這筆資料的頁面在幾毫秒內就更新。

## 使用者得到什麼

- 變化一發生就出現在畫面上，不必等最多五秒。
- 每個分頁都保持最新，不用重新整理。
- 手機不再每隔幾秒白白喚醒網路。

## 輪詢的代價

1,000 人開著頁面、每 5 秒輪詢一次，一小時就是 720,000 個請求。如果這一小時資料只變了 200 次，其中 99.97% 的請求都沒有新內容。改用推送，同一個小時只要 200 則訊息，你的 API 只需要處理每個頁面第一次載入。

## 用到的功能

- **私人頻道**（`private-order-42`），頁面上顯示的每一樣東西一個頻道，由你的伺服器授權，使用者只會收到自己的資料。
- 官方伺服器 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/zh-tw/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 路由、worker、後台操作、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/zh-tw/use-cases/live-dashboards)。
- 經常變動的清單可以一個清單一個頻道（`private-orders-team-7`），不必每一列一個。
- 事件大小依方案而定，請看[價格](https://hibira.io/zh-tw/pricing)。
- 想在發布前知道有多少人在看？請看[即時在線人數](https://hibira.io/zh-tw/use-cases/online-user-counts)。
