Vào năm 2015, chúng tôi ra mắt tính năng Đồng bộ hoá trong nền, cho phép trình chạy dịch vụ trì hoãn công việc cho đến khi người dùng có kết nối. Điều này có nghĩa là người dùng có thể nhập tin nhắn, nhấn gửi và rời khỏi trang web khi biết rằng tin nhắn sẽ được gửi ngay bây giờ hoặc khi họ có kết nối.
Đây là một tính năng hữu ích nhưng đòi hỏi trình chạy dịch vụ phải hoạt động trong suốt thời gian tìm nạp. Đó không phải là vấn đề đối với các công việc ngắn như gửi tin nhắn, nhưng nếu tác vụ mất quá nhiều thời gian, trình duyệt sẽ tắt trình chạy dịch vụ, nếu không thì có rủi ro đối với quyền riêng tư và pin của người dùng.
Vậy, giả sử bạn cần tải nội dung có thể mất nhiều thời gian, chẳng hạn như phim, podcast hoặc cấp độ trò chơi. Đó là mục đích của Tìm nạp trong nền.
Tính năng Tìm nạp trong nền hoạt động theo mặc định kể từ Chrome 74.
Sau đây là bản minh hoạ nhanh trong 2 phút cho thấy trạng thái truyền thống của mọi việc so với cách sử dụng Tìm nạp trong nền:
Tự dùng thử bản minh hoạ và duyệt xem mã.
Cách thức hoạt động
Quy trình tìm nạp trong nền hoạt động như sau:
- Bạn yêu cầu trình duyệt thực hiện một nhóm tìm nạp ở chế độ nền.
- Trình duyệt tìm nạp những thứ đó và hiển thị tiến trình cho người dùng.
- Sau khi tìm nạp xong hoặc không thành công, trình duyệt sẽ mở trình chạy dịch vụ của bạn và kích hoạt một sự kiện để cho bạn biết điều gì đã xảy ra. Đây là nơi bạn quyết định việc cần làm với câu trả lời (nếu có).
Nếu người dùng đóng các trang đến trang web của bạn sau bước 1 thì không có vấn đề gì, quá trình tải xuống sẽ tiếp tục. Vì hoạt động tìm nạp rất hiển thị và dễ dàng huỷ bỏ, nên bạn không cần lo ngại về quyền riêng tư khi thực hiện tác vụ đồng bộ hoá ở chế độ nền kéo dài. Vì trình chạy dịch vụ không hoạt động liên tục, nên bạn không cần lo lắng về việc trình chạy này có thể sử dụng hệ thống sai mục đích, chẳng hạn như đào bitcoin ở chế độ nền.
Trên một số nền tảng (chẳng hạn như Android), trình duyệt có thể đóng sau bước 1, vì trình duyệt có thể chuyển giao quá trình tìm nạp cho hệ điều hành.
Nếu người dùng bắt đầu tải xuống khi không có mạng hoặc không có kết nối mạng trong quá trình tải xuống, thì quá trình tìm nạp trong nền sẽ bị tạm dừng và tiếp tục sau đó.
API
Phát hiện tính năng
Giống như bất kỳ tính năng mới nào, bạn nên xem trình duyệt có hỗ trợ tính năng đó hay không. Đối với Tìm nạp trong nền, quy trình này đơn giản như:
if ('BackgroundFetchManager' in self) {
// This browser supports Background Fetch!
}
Bắt đầu tìm nạp trong nền
API chính sẽ tạm ngưng quy trình đăng ký service worker, vì vậy, hãy đảm bảo bạn đã đăng ký một trình chạy dịch vụ trước tiên. Sau đó:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.fetch('my-fetch', ['/ep-5.mp3', 'ep-5-artwork.jpg'], {
title: 'Episode 5: Interesting things.',
icons: [{
sizes: '300x300',
src: '/ep-5-icon.png',
type: 'image/png',
}],
downloadTotal: 60 * 1024 * 1024,
});
});
backgroundFetch.fetch
nhận ba đối số:
Tham số | |
---|---|
id |
string xác định duy nhất tệp tìm nạp trong nền này.
|
requests |
Array<Request|string>
Những nội dung cần tìm nạp. Chuỗi sẽ được coi là URL và được chuyển thành Request thông qua new Request(theString) .
Bạn có thể tìm nạp mọi thứ từ các nguồn gốc khác, miễn là tài nguyên cho phép việc đó thông qua CORS. Lưu ý: Chrome hiện không hỗ trợ các yêu cầu cần phải kiểm tra CORS. |
options |
Một đối tượng có thể bao gồm: |
options.title |
string Tiêu đề để trình duyệt hiển thị cùng với tiến trình. |
options.icons |
Array<IconDefinition> Một mảng các đối tượng có "src", "size" và "type". |
options.downloadTotal |
number Tổng kích thước của các nội dung phản hồi (sau khi giải nén). Mặc dù đây là yêu cầu không bắt buộc nhưng bạn nên cung cấp thông tin này. Tệp này dùng để cho người dùng biết kích thước của tệp tải xuống và cung cấp thông tin về tiến trình. Nếu bạn không cung cấp thông tin này, trình duyệt sẽ thông báo cho người dùng biết kích thước không xác định và do đó, người dùng có nhiều khả năng sẽ huỷ quá trình tải xuống. Nếu tìm nạp trong nền vượt quá con số đã cung cấp ở đây, thì quá trình này sẽ bị hủy. Hoàn toàn không có vấn đề gì nếu tệp tải xuống nhỏ hơn |
backgroundFetch.fetch
trả về một lời hứa mà sẽ phân giải bằng BackgroundFetchRegistration
. Tôi sẽ trình bày chi tiết về chương trình này sau. Lời hứa sẽ bị từ chối nếu người dùng đã chọn không tải xuống hoặc một trong các thông số được cung cấp không hợp lệ.
Việc cung cấp nhiều yêu cầu cho một lần tìm nạp trong nền cho phép bạn kết hợp mọi thứ theo logic với người dùng. Ví dụ: một bộ phim có thể được chia thành hàng nghìn tài nguyên (thông thường với MPEG-DASH) và đi kèm với các tài nguyên bổ sung như hình ảnh. Một cấp độ của trò chơi có thể được trải rộng trên nhiều tài nguyên JavaScript, hình ảnh và âm thanh. Nhưng đối với người dùng, đó chỉ là "bộ phim", hay "cấp độ".
Đang tải chế độ tìm nạp trong nền hiện có
Bạn có thể sử dụng phương thức tìm nạp trong nền hiện có như sau:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});
...bằng cách chuyển id (mã nhận dạng) của hoạt động tìm nạp trong nền mà bạn muốn. get
trả về undefined
nếu không có phương thức tìm nạp trong nền nào đang hoạt động với mã nhận dạng đó.
Hoạt động tìm nạp trong nền được coi là "đang hoạt động" kể từ thời điểm đăng ký cho đến khi thành công, không thành công hoặc bị huỷ.
Bạn có thể lấy danh sách tất cả các lần tìm nạp trong nền đang hoạt động bằng cách sử dụng getIds
:
navigator.serviceWorker.ready.then(async (swReg) => {
const ids = await swReg.backgroundFetch.getIds();
});
Đăng ký tìm nạp ở chế độ nền
BackgroundFetchRegistration
(bgFetch
trong các ví dụ ở trên) có:
Thuộc tính | |
---|---|
id |
string Mã nhận dạng của tìm nạp trong nền. |
uploadTotal |
number Số byte sẽ được gửi đến máy chủ. |
uploaded |
number Số byte đã gửi thành công. |
downloadTotal |
number Giá trị được cung cấp khi tìm nạp trong nền được đăng ký, hoặc giá trị đó là 0. |
downloaded |
number Số byte đã nhận được. Giá trị này có thể giảm. Ví dụ: nếu kết nối bị gián đoạn và không thể tiếp tục tải xuống, trong trường hợp đó, trình duyệt sẽ khởi động lại quá trình tìm nạp cho tài nguyên đó từ đầu. |
result |
Một trong những giá trị sau:
|
failureReason |
Một trong những giá trị sau:
|
recordsAvailable |
boolean Có thể truy cập vào các yêu cầu/phản hồi cơ bản không? Khi giá trị này là false, |
Phương thức | |
abort() |
Trả về Promise<boolean> Huỷ tìm nạp trong nền. Lời hứa được trả về sẽ phân giải bằng giá trị true nếu huỷ tìm nạp thành công. |
matchAll(request, opts) |
Trả về Promise<Array<BackgroundFetchRecord>> Nhận yêu cầu và phản hồi. Các đối số ở đây giống như API bộ nhớ đệm. Việc gọi không có đối số sẽ trả về một lời hứa cho tất cả các bản ghi. Hãy xem mục bên dưới để biết thêm thông tin. |
match(request, opts) |
Trả về Promise<BackgroundFetchRecord> Như trên, nhưng phân giải bằng kết quả trùng khớp đầu tiên. |
Sự kiện | |
progress |
Được kích hoạt khi bất kỳ uploaded , downloaded , result hoặc failureReason nào thay đổi. |
Theo dõi tiến độ
Bạn có thể thực hiện việc này thông qua sự kiện progress
. Hãy nhớ rằng downloadTotal
là giá trị bất kỳ mà bạn đã cung cấp hoặc 0
nếu bạn không cung cấp giá trị.
bgFetch.addEventListener('progress', () => {
// If we didn't provide a total, we can't provide a %.
if (!bgFetch.downloadTotal) return;
const percent = Math.round(bgFetch.downloaded / bgFetch.downloadTotal * 100);
console.log(`Download progress: ${percent}%`);
});
Nhận yêu cầu và phản hồi
bgFetch.match('/ep-5.mp3').then(async (record) => {
if (!record) {
console.log('No record found');
return;
}
console.log(`Here's the request`, record.request);
const response = await record.responseReady;
console.log(`And here's the response`, response);
});
record
là một BackgroundFetchRecord
và nó sẽ có dạng như sau:
Thuộc tính | |
---|---|
request |
Request Yêu cầu được đưa ra. |
responseReady |
Promise<Response> Câu trả lời đã tìm nạp. Phản hồi này là lời hứa vì có thể chưa nhận được. Lời hứa sẽ bị từ chối nếu tìm nạp không thành công. |
Sự kiện Service worker
Sự kiện | |
---|---|
backgroundfetchsuccess |
Đã tìm nạp thành công mọi thứ. |
backgroundfetchfailure |
Một hoặc nhiều lần tìm nạp không thành công. |
backgroundfetchabort |
Một hoặc nhiều lần tìm nạp không thành công.
Điều này chỉ thực sự hữu ích nếu bạn muốn xoá dữ liệu liên quan. |
backgroundfetchclick |
Người dùng nhấp vào giao diện người dùng tiến trình tải xuống. |
Các đối tượng sự kiện có những đặc điểm sau:
Thuộc tính | |
---|---|
registration |
BackgroundFetchRegistration |
Phương thức | |
updateUI({ title, icons }) |
Cho phép bạn thay đổi tiêu đề/biểu tượng mà bạn đã đặt ban đầu. Bạn không bắt buộc phải thực hiện việc này nhưng sẽ cung cấp thêm ngữ cảnh nếu cần. Bạn chỉ có thể làm việc này *một lần* trong các sự kiện backgroundfetchsuccess và backgroundfetchfailure . |
Phản ứng khi thành công/thất bại
Chúng ta đã thấy sự kiện progress
, nhưng điều này chỉ hữu ích khi người dùng có một trang đang mở đến trang web của bạn. Lợi ích chính của tính năng tìm nạp trong nền là mọi thứ vẫn tiếp tục hoạt động sau khi người dùng rời khỏi trang hoặc thậm chí là đóng trình duyệt.
Nếu hoàn tất thành công tìm nạp trong nền, trình chạy dịch vụ của bạn sẽ nhận được sự kiện
backgroundfetchsuccess
và event.registration
sẽ là đăng ký tìm nạp trong nền.
Sau sự kiện này, bạn sẽ không thể truy cập vào các yêu cầu và phản hồi đã tìm nạp nữa. Vì vậy, nếu bạn muốn giữ lại những yêu cầu và phản hồi này, hãy di chuyển chúng đến một nơi nào đó như API bộ nhớ đệm.
Tương tự như với hầu hết các sự kiện của trình chạy dịch vụ, hãy sử dụng event.waitUntil
để trình chạy dịch vụ biết thời điểm sự kiện hoàn tất.
Ví dụ: trong trình chạy dịch vụ:
addEventListener('backgroundfetchsuccess', (event) => {
const bgFetch = event.registration;
event.waitUntil(async function() {
// Create/open a cache.
const cache = await caches.open('downloads');
// Get all the records.
const records = await bgFetch.matchAll();
// Copy each request/response across.
const promises = records.map(async (record) => {
const response = await record.responseReady;
await cache.put(record.request, response);
});
// Wait for the copying to complete.
await Promise.all(promises);
// Update the progress notification.
event.updateUI({ title: 'Episode 5 ready to listen!' });
}());
});
Lỗi có thể đã xảy ra với một lỗi 404 mà có thể không quan trọng đối với bạn, vì vậy, bạn vẫn nên sao chép một số phản hồi vào bộ nhớ đệm như trên.
Bày tỏ cảm xúc khi nhấp vào
Giao diện người dùng cho thấy tiến trình tải xuống và kết quả tải xuống có thể nhấp vào được. Sự kiện backgroundfetchclick
trong trình chạy dịch vụ cho phép bạn phản ứng với việc này. Như trên, event.registration
sẽ là đăng ký tìm nạp trong nền.
Bạn có thể mở một cửa sổ để sử dụng sự kiện này:
addEventListener('backgroundfetchclick', (event) => {
const bgFetch = event.registration;
if (bgFetch.result === 'success') {
clients.openWindow('/latest-podcasts');
} else {
clients.openWindow('/download-progress');
}
});
Tài nguyên khác
Đính chính: Phiên bản trước của bài viết này gọi nhầm Tìm nạp trong nền là một "tiêu chuẩn web". API này hiện chưa có trong kênh tiêu chuẩn. Bạn có thể tìm thấy thông số kỹ thuật trong WICG dưới dạng Báo cáo nhóm cộng đồng nháp.