Tóm tắt
Kể từ Chrome 68, theo mặc định, bộ nhớ đệm HTTP sẽ không thực hiện các yêu cầu HTTP kiểm tra bản cập nhật cho tập lệnh của worker dịch vụ nữa. Điều này giải quyết một điểm đau thường gặp của nhà phát triển, trong đó việc vô tình đặt tiêu đề Cache-Control
trên tập lệnh worker dịch vụ có thể dẫn đến việc cập nhật bị chậm trễ.
Nếu đã chọn không lưu vào bộ nhớ đệm HTTP cho tập lệnh /service-worker.js
bằng cách phân phát tập lệnh đó bằng Cache-Control: max-age=0
, thì bạn sẽ không thấy thay đổi nào do hành vi mặc định mới.
Ngoài ra, kể từ Chrome 78, tính năng so sánh byte cho byte sẽ được áp dụng cho các tập lệnh được tải trong trình chạy dịch vụ thông qua importScripts()
.
Mọi thay đổi đối với tập lệnh đã nhập sẽ kích hoạt quy trình cập nhật trình chạy dịch vụ, giống như khi thay đổi trình chạy dịch vụ cấp cao nhất.
Thông tin khái quát
Mỗi khi bạn chuyển đến một trang mới thuộc phạm vi của worker dịch vụ, hãy gọi rõ ràng registration.update()
từ JavaScript hoặc khi worker dịch vụ được "đánh thức" thông qua sự kiện push
hoặc sync
, trình duyệt sẽ đồng thời yêu cầu tài nguyên JavaScript ban đầu được truyền vào lệnh gọi navigator.serviceWorker.register()
để tìm nội dung cập nhật cho tập lệnh worker dịch vụ.
Đối với mục đích của bài viết này, hãy giả sử URL của tệp là /service-worker.js
và tệp này chứa một lệnh gọi duy nhất đến importScripts()
. Lệnh gọi này sẽ tải mã bổ sung chạy bên trong worker dịch vụ:
// Inside our /service-worker.js file:
importScripts('path/to/import.js');
// Other top-level code goes here.
Điều gì sẽ thay đổi?
Trước Chrome 68, yêu cầu cập nhật cho /service-worker.js
sẽ được thực hiện thông qua bộ nhớ đệm HTTP (như hầu hết các yêu cầu tìm nạp). Điều này có nghĩa là nếu tập lệnh ban đầu được gửi bằng Cache-Control:
max-age=600
, thì các bản cập nhật trong vòng 600 giây tiếp theo (10 phút) sẽ không được gửi đến mạng, vì vậy, người dùng có thể không nhận được phiên bản mới nhất của worker dịch vụ. Tuy nhiên, nếu max-age
lớn hơn 86400 (24 giờ), thì giá trị này sẽ được coi là 86400 để tránh người dùng bị mắc kẹt mãi mãi với một phiên bản cụ thể.
Kể từ phiên bản 68, bộ nhớ đệm HTTP sẽ bị bỏ qua khi yêu cầu cập nhật tập lệnh trình chạy dịch vụ. Vì vậy, các ứng dụng web hiện có có thể thấy tần suất yêu cầu tập lệnh trình chạy dịch vụ tăng lên. Các yêu cầu đối với importScripts
vẫn sẽ được thực hiện thông qua bộ nhớ đệm HTTP. Tuy nhiên, đây chỉ là chế độ mặc định. Bạn có thể sử dụng tuỳ chọn đăng ký mới updateViaCache
để kiểm soát hành vi này.
updateViaCache
Giờ đây, nhà phát triển có thể truyền một tuỳ chọn mới khi gọi navigator.serviceWorker.register()
: tham số updateViaCache
.
Thuộc tính này có một trong ba giá trị: 'imports'
, 'all'
hoặc 'none'
.
Các giá trị này xác định xem bộ nhớ đệm HTTP tiêu chuẩn của trình duyệt có được sử dụng hay không và cách thức sử dụng khi tạo yêu cầu HTTP để kiểm tra các tài nguyên của worker dịch vụ đã cập nhật.
Khi được đặt thành
'imports'
, bộ nhớ đệm HTTP sẽ không bao giờ được tham khảo khi kiểm tra nội dung cập nhật cho tập lệnh/service-worker.js
, nhưng sẽ được tham khảo khi tìm nạp bất kỳ tập lệnh nào đã nhập (path/to/import.js
trong ví dụ của chúng tôi). Đây là hành vi mặc định và khớp với hành vi bắt đầu từ Chrome 68.Khi được đặt thành
'all'
, bộ nhớ đệm HTTP sẽ được tham khảo khi tạo yêu cầu cho cả tập lệnh/service-worker.js
cấp cao nhất cũng như mọi tập lệnh được nhập bên trong worker dịch vụ, chẳng hạn nhưpath/to/import.js
. Tuỳ chọn này tương ứng với hành vi trước đó trong Chrome, trước Chrome 68.Khi được đặt thành
'none'
, bộ nhớ đệm HTTP sẽ không được tham khảo khi tạo yêu cầu cho/service-worker.js
cấp cao nhất hoặc cho bất kỳ tập lệnh nào được nhập, chẳng hạn nhưpath/to/import.js
giả định.
Ví dụ: mã sau đây sẽ đăng ký một worker dịch vụ và đảm bảo rằng bộ nhớ đệm HTTP không bao giờ được tham khảo khi kiểm tra nội dung cập nhật cho tập lệnh /service-worker.js
hoặc cho bất kỳ tập lệnh nào được tham chiếu thông qua importScripts()
bên trong /service-worker.js
:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js', {
updateViaCache: 'none',
// Optionally, set 'scope' here, if needed.
});
}
Kiểm tra các bản cập nhật cho tập lệnh đã nhập
Trước Chrome 78, mọi tập lệnh của worker dịch vụ được tải qua importScripts()
sẽ chỉ được truy xuất một lần (trước tiên hãy kiểm tra với bộ nhớ đệm HTTP hoặc qua mạng, tuỳ thuộc vào cấu hình updateViaCache
). Sau lần truy xuất ban đầu đó, trình duyệt sẽ lưu trữ nội dung này trong nội bộ và không bao giờ tìm nạp lại.
Cách duy nhất để buộc một worker dịch vụ đã cài đặt nhận các thay đổi đối với tập lệnh đã nhập là thay đổi URL của tập lệnh, thường là bằng cách thêm giá trị semver (ví dụ: importScripts('https://example.com/v1.1.0/index.js')
) hoặc bằng cách thêm hàm băm của nội dung (ví dụ: importScripts('https://example.com/index.abcd1234.js')
). Một tác dụng phụ của việc thay đổi URL đã nhập là nội dung của tập lệnh worker dịch vụ cấp cao nhất sẽ thay đổi, từ đó kích hoạt quy trình cập nhật worker dịch vụ.
Kể từ Chrome 78, mỗi lần kiểm tra bản cập nhật cho một tệp trình chạy dịch vụ cấp cao nhất, hệ thống sẽ đồng thời kiểm tra để xác định xem nội dung của bất kỳ tập lệnh nào đã nhập có thay đổi hay không. Tuỳ thuộc vào tiêu đề Cache-Control
được sử dụng, các lượt kiểm tra tập lệnh đã nhập này có thể được thực hiện bằng bộ nhớ đệm HTTP nếu updateViaCache
được đặt thành 'all'
hoặc 'imports'
(là giá trị mặc định) hoặc các lượt kiểm tra có thể trực tiếp truy cập vào mạng nếu updateViaCache
được đặt thành 'none'
.
Nếu quá trình kiểm tra bản cập nhật cho một tập lệnh đã nhập dẫn đến sự khác biệt về byte so với nội dung mà worker dịch vụ đã lưu trữ trước đó, thì điều này sẽ kích hoạt toàn bộ quy trình cập nhật worker dịch vụ, ngay cả khi tệp worker dịch vụ cấp cao nhất vẫn giữ nguyên.
Hành vi của Chrome 78 khớp với hành vi mà Firefox triển khai vài năm trước, trong Firefox 56. Safari cũng đã triển khai hành vi này.
Nhà phát triển cần làm gì?
Nếu đã chọn không lưu vào bộ nhớ đệm HTTP cho tập lệnh /service-worker.js
một cách hiệu quả bằng cách phân phát tập lệnh đó bằng Cache-Control: max-age=0
(hoặc một giá trị tương tự), thì bạn sẽ không thấy thay đổi nào do hành vi mặc định mới.
Nếu bạn phân phát tập lệnh /service-worker.js
có bật tính năng lưu vào bộ nhớ đệm HTTP, dù là do chủ ý hay vì đó chỉ là chế độ mặc định cho môi trường lưu trữ của bạn, thì bạn có thể bắt đầu thấy số lượng yêu cầu HTTP bổ sung cho /service-worker.js
tăng lên đối với máy chủ của bạn – đây là những yêu cầu từng được thực hiện bằng bộ nhớ đệm HTTP. Nếu muốn tiếp tục cho phép giá trị tiêu đề Cache-Control
ảnh hưởng đến độ mới của /service-worker.js
, bạn cần bắt đầu đặt updateViaCache: 'all'
một cách rõ ràng khi đăng ký worker dịch vụ.
Do có thể có một lượng lớn người dùng sử dụng các phiên bản trình duyệt cũ, bạn vẫn nên tiếp tục đặt tiêu đề HTTP Cache-Control: max-age=0
trên các tập lệnh của worker dịch vụ, mặc dù các trình duyệt mới hơn có thể bỏ qua các tiêu đề này.
Nhà phát triển có thể tận dụng cơ hội này để quyết định xem họ có muốn chọn rõ ràng các tập lệnh đã nhập khỏi bộ nhớ đệm HTTP ngay bây giờ hay không và thêm updateViaCache: 'none'
vào thông tin đăng ký worker dịch vụ nếu thích hợp.
Phân phát tập lệnh đã nhập
Kể từ Chrome 78, nhà phát triển có thể thấy nhiều yêu cầu HTTP đến hơn cho các tài nguyên được tải qua importScripts()
, vì giờ đây, các yêu cầu này sẽ được kiểm tra để cập nhật.
Nếu bạn muốn tránh lưu lượng truy cập HTTP bổ sung này, hãy đặt tiêu đề Cache-Control
có thời gian tồn tại lâu khi phân phát các tập lệnh chứa semver hoặc hàm băm trong URL và dựa vào hành vi updateViaCache
mặc định của 'imports'
.
Ngoài ra, nếu bạn muốn các tập lệnh đã nhập được kiểm tra để cập nhật thường xuyên, hãy đảm bảo bạn phân phát các tập lệnh đó bằng Cache-Control: max-age=0
hoặc sử dụng updateViaCache: 'none'
.
Tài liệu đọc thêm
"Vòng đời của trình chạy dịch vụ" và "Các phương pháp hay nhất về bộ nhớ đệm và các lỗi về thời gian tối đa", cả hai đều do Jake Archibald viết, là những bài viết nên đọc cho tất cả nhà phát triển triển khai nội dung trên web.