用实时更新取代轮询
别再每隔几秒就问一次 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();
});