Trình chạy dịch vụ mới hơn, theo mặc định

Jeff Posnick
J Jeff Posnick

tl;dr

Kể từ Chrome 68, theo mặc định, các yêu cầu HTTP kiểm tra bản cập nhật cho tập lệnh của trình chạy dịch vụ sẽ không còn được bộ nhớ đệm HTTP thực hiện nữa. Giải pháp này giải quyết một điểm bất thường của nhà phát triển, trong đó việc vô tình đặt tiêu đề Cache-Control trên tập lệnh của trình chạy dịch vụ có thể khiến quá trình cập nhật bị chậm trễ.

Nếu đã chọn không sử dụng tính năng lưu HTTP vào bộ nhớ đệm cho tập lệnh /service-worker.js bằng cách phân phát tập lệnh này với Cache-Control: max-age=0, thì bạn sẽ không thấy bất kỳ 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 theo từng byte sẽ áp dụng cho các tập lệnh được tải trong một 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ư thay đổi đối vớ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 di chuyển đến một trang mới thuộc phạm vi của trình chạy dịch vụ, hãy gọi registration.update() một cách rõ ràng từ JavaScript hoặc khi một trình chạy dịch vụ "đánh thức" thông qua sự kiện push hoặc sync, thì trình duyệt sẽ 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 bản cập nhật cho tập lệnh của trình chạy dịch vụ này.

Trong bài viết này, giả sử URL của URL là /service-worker.js và URL đó chứa một lệnh gọi duy nhất đến importScripts(), có chức năng tải mã bổ sung chạy bên trong trình chạy 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 qua bộ nhớ đệm HTTP (như hầu hết các lần 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, các bản cập nhật trong vòng 600 giây (10 phút) tiếp theo 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 trình chạy dịch vụ. Tuy nhiên, nếu max-age lớn hơn 86400 (24 giờ), thì hệ thống sẽ xử lý như thể mã đó là 86400, để tránh trường hợp người dùng bị mắc kẹt vĩnh viễn 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 đối với 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 sẽ vẫn đi qua bộ nhớ đệm HTTP. Nhưng đây chỉ là lựa chọn mặc định. Tuỳ chọn đăng ký mới có sẵn updateViaCache giúp 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. Phương thức này sẽ nhận một trong ba giá trị: 'imports', 'all' hoặc 'none'.

Các giá trị này xác định xem liệu bộ nhớ đệm HTTP tiêu chuẩn của trình duyệt có hoạt động như thế nào hay không khi thực hiện yêu cầu HTTP để kiểm tra tài nguyên của trình chạy dịch vụ đã cập nhật.

  • Khi bạn đặ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 đối với 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 đã nhập nào (trong ví dụ là path/to/import.js). Đây là tuỳ chọn mặc định và phù hợp với hành vi bắt đầu trong Chrome 68.

  • Khi bạn đặt thành 'all', bộ nhớ đệm HTTP sẽ được tham khảo khi gửi 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 trình chạy 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 bạn đặt thành 'none', bộ nhớ đệm HTTP sẽ không được tham khảo khi gửi yêu cầu cho /service-worker.js cấp cao nhất hoặc cho bất kỳ tập lệnh đã nhập nào, chẳng hạn như path/to/import.js giả định.

Ví dụ: Mã sau đây sẽ đăng ký một trình chạy 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 bản cập nhật cho tập lệnh /service-worker.js hoặc bất kỳ tập lệnh nào được tham chiếu 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 bản cập nhật cho các tập lệnh đã nhập

Trước Chrome 78, mọi tập lệnh trình chạy dịch vụ được tải qua importScripts() sẽ chỉ được truy xuất một lần (trước tiên, kiểm tra dựa trên bộ nhớ đệm HTTP hoặc thông 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ữ dữ liệu trong nội bộ và không bao giờ được tìm nạp lại.

Cách duy nhất để buộc một trình chạy dịch vụ đã cài đặt nhận 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ị trình mô phỏng (ví dụ: importScripts('https://example.com/v1.1.0/index.js')) hoặc thêm hàm băm của nội dung (ví dụ: importScripts('https://example.com/index.abcd1234.js')). Tác dụng phụ của việc thay đổi URL đã nhập là nội dung của trình chạy dịch vụ cấp cao nhất thay đổi, cập nhật điều này sẽ kích hoạt luồng dữ liệu.

Kể từ Chrome 78, mỗi lần quy trình kiểm tra bản cập nhật được thực hiện đối với tệp trình chạy dịch vụ cấp cao nhất, các hoạt động kiểm tra sẽ được thực hiện cùng lúc để 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 bước kiểm tra tập lệnh đã nhập này có thể được bộ nhớ đệm HTTP thực hiện nếu updateViaCache được đặt thành 'all' hoặc 'imports' (là giá trị mặc định) hoặc các bước kiểm tra có thể trực tiếp dựa 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ự chênh lệch từng byte so với nội dung mà trình chạy dịch vụ lưu trữ trước đó, thì điều đó sẽ kích hoạt quy trình cập nhật của trình chạy dịch vụ đầy đủ, ngay cả khi tệp trình chạy 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.

Việc nhà phát triển cần làm

Nếu đã chọn không lưu vào bộ nhớ đệm HTTP một cách hiệu quả cho tập lệnh /service-worker.js bằng cách phân phát tập lệnh này với Cache-Control: max-age=0 (hoặc một giá trị tương tự), thì bạn sẽ không thấy bất kỳ thay đổi nào do hành vi mặc định mới.

Nếu 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à cố ý hay chỉ là 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 được thực hiện trên máy chủ của mình — đây là những yêu cầu từng được bộ nhớ đệm HTTP thực hiện. 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 thiết lập updateViaCache: 'all' một cách rõ ràng khi đăng ký trình chạy dịch vụ.

Do có thể có nhiều người dùng trên 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 tập lệnh trình chạy dịch vụ, mặc dù các trình duyệt mới hơn có thể bỏ qua các tập lệnh này.

Nhà phát triển có thể tận dụng cơ hội này để quyết định xem hiện tại họ có muốn chọn rõ ràng các tập lệnh đã nhập khỏi bộ nhớ đệm HTTP hay không, và thêm updateViaCache: 'none' vào phần đăng ký trình chạy dịch vụ nếu thích hợp.

Đang 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ì các tài nguyên này từ nay sẽ được kiểm tra để tìm bản 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 thiết lập các tiêu đề Cache-Control dài hạn 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 muốn kiểm tra các tập lệnh đã nhập để xem có bản cập nhật thường xuyên hay không, 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 bạn sử dụng updateViaCache: 'none'.

Tài liệu đọc thêm

"The Service Lifecycle Lifecycle" và "Các phương pháp hay nhất để lưu vào bộ nhớ đệm và phương pháp tối đa hoá thời gian sử dụng", cả hai đều của Jake Archibald, là những cuốn sách nên đọc đối với tất cả các nhà phát triển triển khai bất kỳ thứ gì lên web.