Cho đến bây giờ, mới chỉ có các lượt đề cập và các đoạn mã nhỏ của
Giao diện Cache
.
Để sử dụng trình chạy dịch vụ một cách hiệu quả, cần áp dụng một hoặc nhiều chiến lược lưu vào bộ nhớ đệm,
yêu cầu người dùng phải làm quen với giao diện Cache
.
Chiến lược lưu vào bộ nhớ đệm là hoạt động tương tác giữa sự kiện fetch
của trình chạy dịch vụ và giao diện Cache
.
Cách viết chiến lược lưu vào bộ nhớ đệm phụ thuộc vào
ví dụ: chúng tôi có thể ưu tiên xử lý các yêu cầu về tài sản tĩnh khác với tài liệu,
và điều này ảnh hưởng đến cách cấu trúc chiến lược lưu vào bộ nhớ đệm.
Trước khi chúng ta tìm hiểu về các chiến lược,
hãy dành chút thời gian để nói về đặc điểm của giao diện Cache
,
và xem nhanh một số phương thức mà công cụ này cung cấp để quản lý bộ nhớ đệm của trình chạy dịch vụ.
Giao diện Cache
so với bộ nhớ đệm HTTP
Nếu trước đây bạn chưa từng làm việc với giao diện Cache
,
bạn có thể nghĩ rằng điều đó giống như
hoặc ít nhất là liên quan đến bộ nhớ đệm HTTP. Tuy nhiên, trường hợp này không đúng.
- Giao diện
Cache
là một cơ chế lưu vào bộ nhớ đệm hoàn toàn tách biệt với bộ nhớ đệm HTTP. - Bất kỳ thứ gì
Cache-Control
mà bạn sử dụng để tác động đến bộ nhớ đệm HTTP sẽ không ảnh hưởng đến nội dung được lưu trữ trong giao diệnCache
.
Điều này giúp bạn hình dung bộ nhớ đệm của trình duyệt được phân lớp. Bộ nhớ đệm HTTP là một bộ nhớ đệm cấp thấp do các cặp khoá-giá trị điều khiển, có lệnh được thể hiện trong tiêu đề HTTP.
Ngược lại, giao diện Cache
là bộ nhớ đệm cấp cao do API JavaScript điều khiển.
Điều này mang lại tính linh hoạt cao hơn so với khi sử dụng cặp khoá-giá trị HTTP tương đối đơn giản.
là một nửa trong số những điều giúp
tạo ra chiến lược lưu vào bộ nhớ đệm.
Một số phương thức API quan trọng liên quan đến bộ nhớ đệm của trình chạy dịch vụ là:
CacheStorage.open
để tạo một phiên bảnCache
mới.Cache.add
vàCache.put
để lưu trữ phản hồi mạng trong bộ nhớ đệm của trình chạy dịch vụ.Cache.match
để tìm phản hồi được lưu vào bộ nhớ đệm trong thực thểCache
.Cache.delete
để xoá phản hồi đã lưu vào bộ nhớ đệm khỏi thực thểCache
.
Đây chỉ là một vài trong số đó. Có những phương pháp hữu ích khác, nhưng đây là những phương pháp cơ bản mà bạn sẽ thấy trong phần sau của hướng dẫn này.
Sự kiện đơn giản ở fetch
Nửa còn lại của chiến lược lưu vào bộ nhớ đệm là
Sự kiện fetch
.
Cho đến bây giờ, trong tài liệu này, bạn đã nghe nói một chút về việc "chặn yêu cầu mạng",
và sự kiện fetch
bên trong một trình chạy dịch vụ là nơi điều này xảy ra:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('install', (event) => {
event.waitUntil(caches.open(cacheName));
});
self.addEventListener('fetch', async (event) => {
// Is this a request for an image?
if (event.request.destination === 'image') {
// Open the cache
event.respondWith(caches.open(cacheName).then((cache) => {
// Respond with the image from the cache or from the network
return cache.match(event.request).then((cachedResponse) => {
return cachedResponse || fetch(event.request.url).then((fetchedResponse) => {
// Add the network response to the cache for future visits.
// Note: we need to make a copy of the response to save it in
// the cache and use the original as the request response.
cache.put(event.request, fetchedResponse.clone());
// Return the network response
return fetchedResponse;
});
});
}));
} else {
return;
}
});
Đây là một ví dụ về đồ chơi và quy trình mà bạn có thể thấy ngay trong thực tế, nhưng đây là một cơ chế cung cấp thông tin sơ lược về những việc mà worker có thể làm. Đoạn mã trên sẽ thực hiện những việc sau:
- Hãy kiểm tra thuộc tính
destination
của yêu cầu để xem đây có phải là yêu cầu hình ảnh hay không. - Nếu hình ảnh nằm trong bộ nhớ đệm của trình chạy dịch vụ, hãy phân phát hình ảnh đó từ đó. Nếu không, hãy tìm nạp hình ảnh từ mạng lưu trữ phản hồi trong bộ nhớ đệm và trả về phản hồi mạng.
- Tất cả các yêu cầu khác được chuyển qua trình chạy dịch vụ mà không có tương tác với bộ nhớ đệm.
Đối tượng event
của lần tìm nạp chứa
Tài sản request
một số thông tin hữu ích giúp bạn xác định loại của mỗi yêu cầu:
url
! đây là URL cho yêu cầu mạng hiện đang được sự kiệnfetch
xử lý.method
! là phương thức yêu cầu (ví dụ:GET
hoặcPOST
).mode
! Mô tả chế độ của yêu cầu. Giá trị của'navigate'
thường được dùng để phân biệt yêu cầu đối với tài liệu HTML với các yêu cầu khác.destination
! mô tả loại nội dung được yêu cầu theo cách tránh sử dụng đuôi tệp của nội dung được yêu cầu.
Một lần nữa, không đồng bộ là tên của trò chơi.
Bạn sẽ nhớ rằng sự kiện install
cung cấp
event.waitUntil
một phương thức hứa hẹn và chờ giải quyết trước khi tiếp tục kích hoạt.
Sự kiện fetch
cung cấp sự kiện tương tự
Phương thức event.respondWith
mà bạn có thể sử dụng để trả về kết quả của sự kiện không đồng bộ
Yêu cầu fetch
hoặc phản hồi được trả về bởi giao diện Cache
Phương pháp match
.
Chiến lược lưu vào bộ nhớ đệm
Bây giờ, bạn đã quen thuộc với các thực thể Cache
và trình xử lý sự kiện fetch
,
bạn đã sẵn sàng tìm hiểu sâu hơn về một số chiến lược lưu vào bộ nhớ đệm của trình chạy dịch vụ.
Mặc dù thực tế thì khả năng là vô hạn,
hướng dẫn này sẽ bám sát các chiến lược
đi kèm với Workbox,
để bạn có thể nắm được những gì đang diễn ra trong nội bộ của Workbox.
Chỉ bộ nhớ đệm
Hãy bắt đầu với chiến lược lưu vào bộ nhớ đệm đơn giản mà chúng ta sẽ gọi là "Chỉ bộ nhớ đệm". Chỉ là: khi service worker kiểm soát trang, các yêu cầu so khớp sẽ chỉ được chuyển vào bộ nhớ đệm. Điều này có nghĩa là mọi nội dung được lưu vào bộ nhớ đệm sẽ cần được lưu trước vào bộ nhớ đệm để mẫu có thể hoạt động. và những thành phần đó sẽ không bao giờ được cập nhật trong bộ nhớ đệm cho đến khi trình chạy dịch vụ được cập nhật.
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
// Assets to precache
const precachedAssets = [
'/possum1.jpg',
'/possum2.jpg',
'/possum3.jpg',
'/possum4.jpg'
];
self.addEventListener('install', (event) => {
// Precache assets on install
event.waitUntil(caches.open(cacheName).then((cache) => {
return cache.addAll(precachedAssets);
}));
});
self.addEventListener('fetch', (event) => {
// Is this one of our precached assets?
const url = new URL(event.request.url);
const isPrecachedRequest = precachedAssets.includes(url.pathname);
if (isPrecachedRequest) {
// Grab the precached asset from the cache
event.respondWith(caches.open(cacheName).then((cache) => {
return cache.match(event.request.url);
}));
} else {
// Go to the network
return;
}
});
Ở trên, một mảng các thành phần được lưu trước vào bộ nhớ đệm tại thời điểm cài đặt.
Khi service worker xử lý các lần tìm nạp,
chúng tôi sẽ kiểm tra xem URL yêu cầu do sự kiện fetch
xử lý có nằm trong mảng tài sản được lưu trước đã lưu vào bộ nhớ đệm hay không.
Nếu vậy, chúng ta sẽ lấy tài nguyên từ bộ nhớ đệm và bỏ qua mạng.
Các yêu cầu khác đi qua mạng,
và chỉ mạng.
Để xem chiến lược này trong thực tế,
xem bản minh hoạ này khi bảng điều khiển đang mở.
Chỉ với mạng
Trái ngược với "Chỉ bộ nhớ đệm" là "Chỉ mạng", nơi yêu cầu được chuyển thông qua một trình chạy dịch vụ tới mạng mà không có bất kỳ sự tương tác nào với bộ nhớ đệm của trình chạy dịch vụ. Đây là một chiến lược hay để đảm bảo nội dung mới mẻ (ví dụ như mã đánh dấu), nhưng đổi lại là tính năng này sẽ không bao giờ hoạt động khi người dùng không kết nối mạng.
Việc đảm bảo một yêu cầu đi qua mạng chỉ có nghĩa là bạn không gọi event.respondWith
cho một yêu cầu trùng khớp.
Nếu bạn muốn thể hiện rõ ràng,
bạn có thể chèn một return;
trống trong lệnh gọi lại sự kiện fetch
cho các yêu cầu mà bạn muốn truyền vào mạng.
Đây là những gì xảy ra trong tuỳ chọn "Chỉ bộ nhớ đệm" bản minh hoạ chiến lược cho các yêu cầu không được lưu trước trong bộ nhớ đệm.
Trước tiên, hãy lưu vào bộ nhớ đệm rồi quay lại mạng
Chiến lược này là để mọi thứ trở nên quan trọng hơn một chút. Đối với các yêu cầu so khớp, quy trình này diễn ra như sau:
- Yêu cầu truy cập vào bộ nhớ đệm. Nếu nội dung nằm trong bộ nhớ đệm, hãy phân phát nội dung từ đó.
- Nếu yêu cầu không có trong bộ nhớ đệm, hãy truy cập vào mạng.
- Sau khi hoàn tất yêu cầu mạng, hãy thêm yêu cầu đó vào bộ nhớ đệm thì trả về phản hồi từ mạng.
Sau đây là ví dụ về chiến lược này mà bạn có thể thử nghiệm trong bản minh hoạ trực tiếp:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
// Check if this is a request for an image
if (event.request.destination === 'image') {
event.respondWith(caches.open(cacheName).then((cache) => {
// Go to the cache first
return cache.match(event.request.url).then((cachedResponse) => {
// Return a cached response if we have one
if (cachedResponse) {
return cachedResponse;
}
// Otherwise, hit the network
return fetch(event.request).then((fetchedResponse) => {
// Add the network response to the cache for later visits
cache.put(event.request, fetchedResponse.clone());
// Return the network response
return fetchedResponse;
});
});
}));
} else {
return;
}
});
Mặc dù ví dụ này chỉ đề cập đến hình ảnh, đây là một chiến lược hiệu quả để áp dụng cho tất cả thành phần tĩnh (chẳng hạn như CSS, JavaScript, hình ảnh và phông chữ), đặc biệt là các phiên bản băm. Tính năng này giúp tăng tốc độ cho các tài sản bất biến bằng cách chạy bên cạnh mọi quá trình kiểm tra độ mới của nội dung với máy chủ mà bộ nhớ đệm HTTP có thể bắt đầu. Quan trọng hơn, mọi nội dung được lưu vào bộ nhớ đệm đều sẽ dùng được khi không có mạng.
Ưu tiên kết nối mạng, chuyển lại về bộ nhớ đệm
Nếu bạn định lật "Bộ nhớ đệm trước, giây thứ hai" trên đầu, bạn sẽ kết thúc bằng lời nhắc "Dùng mạng trước, lưu bộ nhớ đệm thứ hai" chiến lược.
- Trước tiên, bạn sẽ truy cập vào mạng để xử lý một yêu cầu rồi đặt phản hồi vào bộ nhớ đệm.
- Nếu sau này bạn không có kết nối mạng, bạn sẽ quay lại phiên bản mới nhất của phản hồi đó trong bộ nhớ đệm.
Chiến lược này phù hợp cho các yêu cầu HTML hoặc API khi trong khi trực tuyến, bạn muốn có phiên bản mới nhất của tài nguyên, nhưng muốn cấp quyền truy cập ngoại tuyến vào phiên bản có sẵn mới nhất. Khi áp dụng cho các yêu cầu đối với HTML, việc này có thể trông giống như sau:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
// Check if this is a navigation request
if (event.request.mode === 'navigate') {
// Open the cache
event.respondWith(caches.open(cacheName).then((cache) => {
// Go to the network first
return fetch(event.request.url).then((fetchedResponse) => {
cache.put(event.request, fetchedResponse.clone());
return fetchedResponse;
}).catch(() => {
// If the network is unavailable, get
return cache.match(event.request.url);
});
}));
} else {
return;
}
});
Bạn có thể dùng thử tính năng này ở bản minh hoạ. Trước tiên, hãy truy cập vào trang. Bạn có thể cần tải lại trước khi phản hồi HTML được đặt vào bộ nhớ đệm. Sau đó, trong công cụ cho nhà phát triển, mô phỏng kết nối ngoại tuyến rồi tải lại. Phiên bản mới nhất hiện có sẽ được phân phát ngay từ bộ nhớ đệm.
Trong trường hợp khả năng ngoại tuyến là quan trọng, nhưng bạn cần phải cân bằng giữa khả năng đó với quyền truy cập vào phiên bản mới nhất của mã đánh dấu hoặc dữ liệu API, "Trước tiên, hãy lưu vào bộ nhớ đệm" là một chiến lược vững chắc để đạt được mục tiêu đó.
Đã cũ trong khi xác thực lại
Trong số các chiến lược mà chúng tôi đã đề cập cho đến thời điểm này, chiến lược "Đã lỗi thời trong khi xác thực lại" là phức tạp nhất. Nó tương tự như hai chiến lược cuối cùng ở một số khía cạnh, nhưng quy trình này ưu tiên tốc độ truy cập tài nguyên, đồng thời tiếp tục cập nhật ứng dụng trong nền. Chiến lược này có dạng như sau:
- Trong yêu cầu đầu tiên đối với một nội dung, hãy tìm nạp nội dung từ mạng. hãy đặt mã đó vào bộ nhớ đệm rồi trả về phản hồi mạng.
- Trong các yêu cầu tiếp theo, phân phát nội dung từ bộ nhớ đệm trước rồi "trong nền" yêu cầu lại từ mạng và cập nhật mục nhập bộ nhớ đệm của nội dung.
- Đối với các yêu cầu sau đó, bạn sẽ nhận được phiên bản cuối cùng được tìm nạp từ mạng đã được đặt trong bộ nhớ đệm ở bước trước.
Đây là một chiến lược tuyệt vời cho những điều quan trọng cần luôn cập nhật, nhưng không quan trọng. Hãy nghĩ đến những nội dung như hình đại diện cho một trang mạng xã hội. Chúng được cập nhật khi người dùng thực hiện việc đó, nhưng phiên bản mới nhất không hoàn toàn cần thiết cho mọi yêu cầu.
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
if (event.request.destination === 'image') {
event.respondWith(caches.open(cacheName).then((cache) => {
return cache.match(event.request).then((cachedResponse) => {
const fetchedResponse = fetch(event.request).then((networkResponse) => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
return cachedResponse || fetchedResponse;
});
}));
} else {
return;
}
});
Bạn có thể xem ví dụ thực tế trong
một bản minh hoạ trực tiếp khác,
đặc biệt nếu bạn chú ý đến tab mạng trong công cụ dành cho nhà phát triển trên trình duyệt của mình,
và trình xem CacheStorage
(nếu công cụ dành cho nhà phát triển trên trình duyệt của bạn có công cụ này).
Chuyển đến Workbox!
Tài liệu này tóm tắt bài đánh giá về API của trình chạy dịch vụ, cũng như các API có liên quan, tức là bạn đã tìm hiểu đủ về cách trực tiếp sử dụng trình chạy dịch vụ để bắt đầu mày mò với Workbox!