Cách trình chạy web và trình chạy dịch vụ có thể cải thiện hiệu suất của trang web, cũng như thời điểm nên sử dụng trình chạy web so với trình chạy dịch vụ.
Thông tin tổng quan này giải thích cách web worker và service worker có thể cải thiện hiệu suất của trang web, cũng như thời điểm nên sử dụng web worker so với service worker. Hãy xem phần còn lại của loạt bài này để biết các mẫu giao tiếp cụ thể của cửa sổ và trình chạy dịch vụ.
Cách các worker có thể cải thiện trang web của bạn
Trình duyệt sử dụng một luồng duy nhất (luồng chính) để chạy tất cả JavaScript trong một trang web, cũng như để thực hiện các tác vụ như kết xuất trang và thực hiện thu gom rác. Việc chạy quá nhiều mã JavaScript có thể chặn luồng chính, khiến trình duyệt không thực hiện được các tác vụ này và dẫn đến trải nghiệm người dùng kém.
Trong quá trình phát triển ứng dụng iOS/Android, một mẫu phổ biến để đảm bảo luồng chính của ứng dụng vẫn có thể phản hồi các sự kiện của người dùng là chuyển các thao tác sang các luồng bổ sung. Trên thực tế, trong các phiên bản Android mới nhất, việc chặn luồng chính quá lâu sẽ dẫn đến sự cố ứng dụng.
Trên web, JavaScript được thiết kế dựa trên khái niệm về một luồng duy nhất và thiếu các chức năng cần thiết để triển khai mô hình đa luồng như mô hình mà các ứng dụng có, chẳng hạn như bộ nhớ dùng chung.
Mặc dù có những hạn chế này, bạn vẫn có thể đạt được một mẫu tương tự trên web bằng cách sử dụng các worker để chạy tập lệnh trong các luồng nền, cho phép các tập lệnh này thực hiện các thao tác mà không ảnh hưởng đến luồng chính. Worker là một phạm vi JavaScript hoàn chỉnh chạy trên một luồng riêng biệt, không có bộ nhớ dùng chung.
Trong bài đăng này, bạn sẽ tìm hiểu về 2 loại trình chạy (trình chạy web và trình chạy dịch vụ), điểm tương đồng và khác biệt giữa chúng, cũng như các mẫu phổ biến nhất để sử dụng chúng trong các trang web sản xuất.

Trình chạy dịch vụ và trình chạy web
Điểm tương đồng
Trình chạy web và trình chạy dịch vụ là hai loại trình chạy có sẵn cho trang web. Chúng có một số điểm chung:
- Cả hai đều chạy trong một luồng phụ, cho phép mã JavaScript thực thi mà không chặn luồng chính và giao diện người dùng.
- Các đối tượng này không có quyền truy cập vào các đối tượng
Window
vàDocument
, nên không thể tương tác trực tiếp với DOM và có quyền truy cập hạn chế vào các API của trình duyệt.
Sự khác biệt
Có thể bạn nghĩ rằng hầu hết những việc có thể uỷ quyền cho một web worker đều có thể thực hiện trong một service worker và ngược lại, nhưng có những điểm khác biệt quan trọng giữa chúng:
- Không giống như web worker, service worker cho phép bạn chặn các yêu cầu mạng (thông qua sự kiện
fetch
) và theo dõi các sự kiện Push API ở chế độ nền (thông qua sự kiệnpush
). - Một trang có thể tạo ra nhiều worker trên web, nhưng một service worker duy nhất sẽ kiểm soát tất cả các thẻ đang hoạt động trong phạm vi mà nó đã đăng ký.
- Thời gian tồn tại của web worker gắn liền với thẻ mà web worker thuộc về, trong khi vòng đời của service worker không phụ thuộc vào thẻ đó. Vì lý do đó, việc đóng thẻ nơi trình chạy web đang chạy sẽ chấm dứt trình chạy đó, trong khi trình chạy dịch vụ có thể tiếp tục chạy ở chế độ nền, ngay cả khi trang web không có thẻ đang hoạt động nào đang mở.
Trường hợp sử dụng
Sự khác biệt giữa cả hai loại worker cho thấy trong những trường hợp nào bạn có thể muốn sử dụng loại này hoặc loại kia:
Các trường hợp sử dụng cho web worker thường liên quan đến việc chuyển công việc (chẳng hạn như các phép tính phức tạp) sang một luồng thứ cấp để tránh chặn giao diện người dùng.

- Ví dụ: nhóm tạo trò chơi điện tử PROXX muốn để luồng chính trống càng nhiều càng tốt để xử lý thông tin đầu vào của người dùng và ảnh động. Để đạt được điều đó, họ đã sử dụng web worker để chạy logic trò chơi và duy trì trạng thái trên một luồng riêng biệt.

Các tác vụ của service worker thường liên quan nhiều hơn đến việc đóng vai trò là một proxy mạng, xử lý các tác vụ ở chế độ nền và những việc như lưu vào bộ nhớ đệm và hoạt động ngoại tuyến.

Ví dụ: Trong một PWA podcast, bạn có thể muốn cho phép người dùng tải các tập hoàn chỉnh xuống để nghe khi không có mạng. Một worker dịch vụ và đặc biệt là Background Fetch API có thể được dùng cho mục đích đó. Bằng cách đó, nếu người dùng đóng thẻ trong khi tập đang tải xuống, thì tác vụ sẽ không bị gián đoạn.

Công cụ và thư viện
Bạn có thể triển khai hoạt động giao tiếp giữa cửa sổ và worker bằng cách sử dụng các API cấp thấp khác nhau. Rất may, có những thư viện trừu tượng hoá quy trình này, xử lý các trường hợp sử dụng phổ biến nhất. Trong phần này, chúng ta sẽ đề cập đến 2 trong số các công cụ này, lần lượt xử lý cửa sổ cho các worker trên web và service worker: Comlink và Workbox.

Comlink
Comlink là một thư viện RPC nhỏ (1,6k) giúp xử lý nhiều thông tin chi tiết cơ bản khi xây dựng các trang web sử dụng Web Worker. Đối tượng này đã được dùng trong các trang web như PROXX và Squoosh. Bạn có thể xem bản tóm tắt về các động lực và mẫu mã của nó tại đây.
Workbox
Workbox là một thư viện phổ biến để tạo các trang web sử dụng service worker. Nó đóng gói một bộ các phương pháp hay nhất về những việc như lưu vào bộ nhớ đệm, ngoại tuyến, đồng bộ hoá trong nền, v.v. Mô-đun workbox-window
cung cấp một cách thuận tiện để trao đổi thông báo giữa worker dịch vụ và trang.
Các bước tiếp theo
Phần còn lại của loạt bài này tập trung vào các mẫu giao tiếp giữa cửa sổ và worker dịch vụ:
- Hướng dẫn về bộ nhớ đệm bắt buộc: Gọi một trình chạy dịch vụ từ trang để lưu trước các tài nguyên vào bộ nhớ đệm (ví dụ: trong các trường hợp tìm nạp trước).
- Thông báo cập nhật: Gọi trang từ service worker để thông báo về các nội dung cập nhật quan trọng (ví dụ: có phiên bản mới của trang web).
- Giao tiếp hai chiều: Uỷ quyền một tác vụ cho một service worker (ví dụ: tải xuống một tệp có dung lượng lớn) và thông báo cho trang về tiến trình.
Để biết các mẫu giao tiếp giữa cửa sổ và worker trên web, hãy xem: Sử dụng web worker để chạy JavaScript ngoài luồng chính của trình duyệt.