Phương pháp hiện đại
Tính năng đồng bộ hoá trong nền định kỳ cho phép bạn hiển thị nội dung mới khi một ứng dụng web tiến bộ hoặc trang được hỗ trợ bởi worker dịch vụ được khởi chạy. Ứng dụng này thực hiện việc này bằng cách tải dữ liệu xuống ở chế độ nền khi ứng dụng hoặc trang không được sử dụng.
Sử dụng API Đồng bộ hoá định kỳ ở chế độ nền
Sau khi cài đặt worker dịch vụ, hãy sử dụng Permissions API (API Quyền) để truy vấn periodic-background-sync
. Bạn có thể thực hiện việc này từ một cửa sổ hoặc ngữ cảnh worker dịch vụ.
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.
}
Để đăng ký đồng bộ hoá định kỳ, bạn cần có cả thẻ và khoảng thời gian đồng bộ hoá tối thiểu (minInterval
). Thẻ này xác định quá trình đồng bộ hoá đã đăng ký để có thể đăng ký nhiều quá trình đồng bộ hoá. Trong ví dụ bên dưới, tên thẻ là 'content-sync'
và minInterval
là một ngày.
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);
}
});
Gọi periodicSync.getTags()
để truy xuất một mảng thẻ đăng ký. Ví dụ bên dưới sử dụng tên thẻ để xác nhận rằng quá trình cập nhật bộ nhớ đệm đang hoạt động để tránh cập nhật lại.
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();
}
Để phản hồi một sự kiện đồng bộ hoá định kỳ ở chế độ nền, hãy thêm trình xử lý sự kiện periodicsync
vào worker dịch vụ. Đối tượng sự kiện được truyền vào sẽ chứa một thông số thẻ khớp với giá trị được sử dụng trong quá trình đăng ký. Ví dụ: nếu một quá trình đồng bộ hoá nền định kỳ được đăng ký với tên 'content-sync'
, thì event.tag
sẽ là 'content-sync'
.
self.addEventListener('periodicsync', (event) => {
if (event.tag === 'content-sync') {
event.waitUntil(syncContent());
}
});
Khả năng tương thích với trình duyệt
Cách truyền thống
Thay vì cập nhật dữ liệu ở chế độ nền để dữ liệu sẵn sàng khi người dùng tải ứng dụng, cách thức cổ điển chỉ bao gồm việc cập nhật dữ liệu khi tải.
Tài liệu đọc thêm
- Trải nghiệm phong phú hơn khi không có mạng nhờ API Đồng bộ hoá định kỳ trong nền
- API Đồng bộ hoá định kỳ trong nền trên web
Bản minh hoạ
<!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>
html {
box-sizing: border-box;
font-family: system-ui, sans-serif;
color-scheme: dark light;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 1rem;
}
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);
});
}