用即時更新取代輪詢
別再每隔幾秒就問一次 API:每個變化只送一次,減少請求與伺服器負載,變化一發生就顯示。
很多應用是靠「問」來得知變化:每個打開的頁面每隔幾秒就呼叫一次你的 API,看看訂單、工單或報表有沒有變。幾乎每次的答案都是「沒有新的」,但每次都要花一個請求、一次資料庫查詢,還有使用者手機的電量;真的有變化時,也還要等上一個間隔才看得到。用 Hibira,你的伺服器在變化發生時只送一次,所有顯示這筆資料的頁面在幾毫秒內就更新。
使用者得到什麼
- 變化一發生就出現在畫面上,不必等最多五秒。
- 每個分頁都保持最新,不用重新整理。
- 手機不再每隔幾秒白白喚醒網路。
輪詢的代價
1,000 人開著頁面、每 5 秒輪詢一次,一小時就是 720,000 個請求。如果這一小時資料只變了 200 次,其中 99.97% 的請求都沒有新內容。改用推送,同一個小時只要 200 則訊息,你的 API 只需要處理每個頁面第一次載入。
用到的功能
- 私人頻道(
private-order-42),頁面上顯示的每一樣東西一個頻道,由你的伺服器授權,使用者只會收到自己的資料。 - 官方伺服器 SDK 的
trigger,在你儲存變更後立刻呼叫。 pusher:subscription_succeeded,第一次連線和每次重新連線後都會觸發:正是載入目前狀態的時機。
輪詢
每個打開的頁面每 5 秒
GET /api/orders/42
你的 API大多是「沒有新的」
推送
你的 API儲存變更
trigger() 一次Hibira
WebSocket
每個顯示它的頁面立刻更新
步驟 1:找到輪詢迴圈
通常長這樣:
setInterval(async () => {
render(await fetch('/api/orders/42').then((r) => r.json()));
}, 5000);步驟 2:載入一次,然後監聽
照 JavaScript 指南 連線,並為私人頻道準備頻道授權端點。訂閱就緒時載入目前狀態,之後每次變化到達就套用:
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),就在寫入成功後發布:
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() 已經會補上斷線期間的空缺。瀏覽器也可能凍結背景分頁,所以分頁回到前景時再載入一次:
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') load();
});