แนวทางสมัยใหม่
การซิงค์ในเบื้องหลังตามระยะเวลาช่วยให้คุณสามารถแสดงเนื้อหาใหม่เมื่อมีการเปิดหน้าเว็บที่ผู้ปฏิบัติงานสนับสนุนหรือ Progressive Web App ทำงาน ซึ่งทำได้โดยการดาวน์โหลดข้อมูลในเบื้องหลังเมื่อไม่มีการใช้งานแอปหรือหน้าเว็บ
การใช้ Periodic Background Sync API
หลังจากติดตั้ง Service Worker แล้ว ให้ใช้ Permissions API เพื่อค้นหา periodic-background-sync
โดยทําได้จากหน้าต่างหรือบริบทของ Service Worker
const status = await navigator.permissions.query({
name: 'periodic-background-sync',
});
if (status.state === 'granted') {
// Periodic background sync can be used.
} else {
// Periodic background sync cannot be used.
}
การลงทะเบียนการซิงค์เป็นระยะต้องมีทั้งแท็กและช่วงเวลาการซิงค์ขั้นต่ำ (minInterval
) แท็กจะระบุการซิงค์ที่ลงทะเบียนแล้วเพื่อให้สามารถลงทะเบียนการซิงค์หลายรายการได้ ในตัวอย่างด้านล่าง ชื่อแท็กคือ 'content-sync'
และ minInterval
คือ 1 วัน
navigator.serviceWorker.ready.then(async registration => {
try {
await registration.periodicSync.register('get-cats', { minInterval: 24 * 60 * 60 * 1000 });
console.log(Periodic background sync registered.');
} catch (err) {
console.error(err.name, err.message);
}
});
เรียกใช้ periodicSync.getTags()
เพื่อเรียกอาร์เรย์ของแท็กการลงทะเบียน ตัวอย่างด้านล่างใช้ชื่อแท็กเพื่อยืนยันว่าการอัปเดตแคชทำงานอยู่เพื่อหลีกเลี่ยงการอัปเดตอีก
const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
const tags = await registration.periodicSync.getTags();
// Only update content if sync isn't set up.
if (!tags.includes('content-sync')) {
updateContentOnPageLoad();
}
} else {
// If periodic background sync isn't supported, always update.
updateContentOnPageLoad();
}
หากต้องการตอบสนองต่อเหตุการณ์การซิงค์เบื้องหลังตามระยะเวลา ให้เพิ่มตัวแฮนเดิลเหตุการณ์ periodicsync
ให้กับโปรแกรมทำงานของบริการ ออบเจ็กต์เหตุการณ์ที่ส่งไปยังออบเจ็กต์ดังกล่าวจะมีพารามิเตอร์แท็กที่ตรงกับค่าที่ใช้ระหว่างการลงทะเบียน ตัวอย่างเช่น หากมีการลงทะเบียนการซิงค์เบื้องหลังเป็นระยะด้วยชื่อ 'content-sync'
แล้ว event.tag
จะเป็น 'content-sync'
self.addEventListener('periodicsync', (event) => {
if (event.tag === 'content-sync') {
event.waitUntil(syncContent());
}
});
ความเข้ากันได้กับเบราว์เซอร์
วิธีคลาสสิก
แทนที่จะอัปเดตข้อมูลในเบื้องหลังเพื่อให้พร้อมใช้งานเมื่อผู้ใช้โหลดแอป แต่วิธีการเดิมก็คือการอัปเดตข้อมูลในการโหลด
อ่านเพิ่มเติม
- ประสบการณ์แบบออฟไลน์ที่สมบูรณ์ยิ่งขึ้นด้วย Periodic Background Sync API
- API การซิงค์ข้อมูลพื้นหลังตามระยะเวลาบนเว็บ
ข้อมูลประชากร
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="icon"
href=""
/>
<link rel="manifest" href="./manifest.json" />
<title>How to periodically synchronize data in the background</title>
<link rel="stylesheet" href="/style.css" />
<!-- TODO: Devsite - Removed inline handlers -->
<!-- <script src="/script.js" defer></script> -->
</head>
<body>
<h1>How to periodically synchronize data in the background</h1>
<p class="available">Periodic background sync can be used. Install the app first.</p>
<p class="not-available">Periodic background sync cannot be used.</p>
<h2>Last updated</h2>
<p class="last-updated">Never</p>
<h2>Registered tags</h2>
<ul>
<li>None yet.</li>
</ul>
</body>
</html>
CSS
html {
box-sizing: border-box;
font-family: system-ui, sans-serif;
color-scheme: dark light;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 1rem;
}
JS
const available = document.querySelector('.available');
const notAvailable = document.querySelector('.not-available');
const ul = document.querySelector('ul');
const lastUpdated = document.querySelector('.last-updated');
const updateContent = async () => {
const data = await fetch(
'https://worldtimeapi.org/api/timezone/Europe/London.json'
).then((response) => response.json());
return new Date(data.unixtime * 1000);
};
const registerPeriodicBackgroundSync = async (registration) => {
const status = await navigator.permissions.query({
name: 'periodic-background-sync',
});
if (status.state === 'granted' && 'periodicSync' in registration) {
try {
// Register the periodic background sync.
await registration.periodicSync.register('content-sync', {
// An interval of one day.
minInterval: 24 * 60 * 60 * 1000,
});
available.hidden = false;
notAvailable.hidden = true;
// List registered periodic background sync tags.
const tags = await registration.periodicSync.getTags();
if (tags.length) {
ul.innerHTML = '';
}
tags.forEach((tag) => {
const li = document.createElement('li');
li.textContent = tag;
ul.append(li);
});
// Update the user interface with the last periodic background sync data.
const backgroundSyncCache = await caches.open('periodic-background-sync');
if (backgroundSyncCache) {
const backgroundSyncResponse =
backgroundSyncCache.match('/last-updated');
if (backgroundSyncResponse) {
lastUpdated.textContent = `${await fetch('/last-updated').then(
(response) => response.text()
)} (periodic background-sync)`;
}
}
// Listen for incoming periodic background sync messages.
navigator.serviceWorker.addEventListener('message', async (event) => {
if (event.data.tag === 'content-sync') {
lastUpdated.textContent = `${await updateContent()} (periodic background sync)`;
}
});
} catch (err) {
console.error(err.name, err.message);
available.hidden = true;
notAvailable.hidden = false;
lastUpdated.textContent = 'Never';
}
} else {
available.hidden = true;
notAvailable.hidden = false;
lastUpdated.textContent = `${await updateContent()} (manual)`;
}
};
if ('serviceWorker' in navigator) {
window.addEventListener('load', async () => {
const registration = await navigator.serviceWorker.register('./sw.js');
console.log('Service worker registered for scope', registration.scope);
await registerPeriodicBackgroundSync(registration);
});
}