เลิกโพลลิงแล้วใช้การอัปเดตแบบเรียลไทม์
เลิกถาม API ทุกไม่กี่วินาที ส่งการเปลี่ยนแปลงแต่ละครั้งเพียงครั้งเดียว ลดคำขอและภาระเซิร์ฟเวอร์ และแสดงอัปเดตทันทีที่เกิดขึ้น
หลายแอปรู้ว่ามีอะไรเปลี่ยนด้วยการ "ถาม": ทุกหน้าที่เปิดอยู่จะเรียก API ทุกไม่กี่วินาทีเพื่อดูว่าคำสั่งซื้อ ทิกเก็ต หรือรายงานเปลี่ยนหรือยัง คำตอบแทบทุกครั้งคือ "ไม่มีอะไรใหม่" แต่ทุกครั้งต้องเสียคำขอหนึ่งครั้ง คิวรีฐานข้อมูลหนึ่งครั้ง และแบตเตอรี่มือถือของผู้ใช้ ส่วนการเปลี่ยนแปลงจริงก็ยังต้องรอถึงรอบถัดไปกว่าจะเห็น เมื่อใช้ Hibira เซิร์ฟเวอร์จะส่งการเปลี่ยนแปลงเพียงครั้งเดียวตอนที่มันเกิดขึ้น และทุกหน้าที่แสดงข้อมูลนั้นจะอัปเดตภายในไม่กี่มิลลิวินาที
ผู้ใช้ของคุณได้อะไร
- เห็นการเปลี่ยนแปลงทันทีที่เกิดขึ้น ไม่ต้องรอสูงสุดห้าวินาที
- ทุกแท็บเป็นข้อมูลล่าสุดเสมอโดยไม่ต้องรีโหลด
- มือถือไม่ต้องปลุกสัญญาณเครือข่ายทุกไม่กี่วินาทีโดยเปล่าประโยชน์
ต้นทุนของการโพล
ผู้ใช้ 1,000 คนเปิดหน้าไว้และโพลทุก 5 วินาที เท่ากับ 720,000 คำขอต่อชั่วโมง ถ้าในชั่วโมงนั้นข้อมูลเปลี่ยนเพียง 200 ครั้ง คำขอ 99.97% จะไม่มีอะไรใหม่เลย เมื่อเปลี่ยนเป็นการพุช ชั่วโมงเดียวกันใช้เพียง 200 ข้อความ และ API ของคุณรับแค่การโหลดครั้งแรกของแต่ละหน้า
สร้างด้วย
- ช่องส่วนตัว (
private-order-42) หนึ่งช่องต่อสิ่งที่หน้าเว็บแสดง เซิร์ฟเวอร์ของคุณเป็นผู้อนุญาต ผู้ใช้จึงได้รับเฉพาะข้อมูลของตัวเอง triggerใน SDK ฝั่งเซิร์ฟเวอร์อย่างเป็นทางการ เรียกทันทีหลังบันทึกการเปลี่ยนแปลงpusher:subscription_succeededซึ่งเกิดขึ้นตอนเชื่อมต่อครั้งแรกและทุกครั้งหลังเชื่อมต่อใหม่ จึงเป็นจังหวะที่เหมาะกับการโหลดสถานะปัจจุบัน
การโพล
การพุช
trigger() ครั้งเดียวขั้นตอนที่ 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: ส่งการเปลี่ยนแปลงตอนบันทึก
ไม่ว่าข้อมูลจะเปลี่ยนที่ไหน (route ของ 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();
});เคล็ดลับ
- ส่งเฉพาะสิ่งที่หน้าเว็บต้องใช้วาดใหม่ ถ้าข้อมูลใหญ่ให้ส่งแค่ ID กับเวอร์ชัน แล้วให้หน้าเว็บดึงส่วนที่เหลือเอง
- ข้อมูลเดียวกันเปลี่ยนหลายครั้งต่อวินาที? รวมเป็นชุดแบบในแดชบอร์ดเรียลไทม์
- รายการที่เปลี่ยนบ่อยใช้หนึ่งช่องต่อรายการ (
private-orders-team-7) แทนหนึ่งช่องต่อแถวได้ - ขนาดของอีเวนต์ขึ้นอยู่กับแพ็กเกจ ดูที่ราคา
- อยากรู้ว่ามีคนดูอยู่กี่คนก่อนส่ง? ดูที่จำนวนผู้ใช้ออนไลน์