Phong cách hiện đại
Tính năng đồng bộ hoá định kỳ ở chế độ nền cho phép bạn hiển thị nội dung mới khi khởi chạy một trang dựa trên trình chạy dịch vụ hoặc ứng dụng web tiến bộ được khởi chạy. Trình phân tích cú pháp thực hiện việc này bằng cách tải dữ liệu xuống ở chế độ nền khi bạn không dùng ứng dụng hoặc trang.
Sử dụng API đồng bộ hoá định kỳ ở chế độ nền
Sau khi cài đặt trình chạy 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 trình chạy 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.
}
Việc đăng ký đồng bộ hoá định kỳ yêu cầu cả thẻ và khoảng thời gian đồng bộ hoá tối thiểu (minInterval
). Thẻ xác định lượt đồng bộ hoá đã đăng ký để có thể đăng ký nhiều lượt đồ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 tính năng cập nhật bộ nhớ đệm đang hoạt động nhằm 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 một trình xử lý sự kiện periodicsync
vào trình chạy dịch vụ. Đối tượng sự kiện được chuyển đến sự kiện đó sẽ chứa thông số thẻ khớp với giá trị được dùng trong quá trình đăng ký. Ví dụ: nếu quá trình đồng bộ hoá định kỳ ở chế độ nền đượ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 cổ điển
Thay vì cập nhật dữ liệu trong nền để dữ liệu sẵn sàng khi người dùng tải ứng dụng, cách cũ chỉ đơn giản là cập nhật dữ liệu khi tải.
Tài liệu đọc thêm
- Trải nghiệm ngoại tuyến phong phú hơn với API đồng bộ hoá định kỳ ở chế độ nền
- API Đồng bộ hoá định kỳ ở chế độ nền trên web
Bản minh hoạ
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);
});
}