Ứng dụng web tiến bộ: Sử dụng Worker

1. Chào mừng bạn

Trong lớp học này, bạn sẽ lấy một ứng dụng web hiện có và thêm web worker để chia sẻ trạng thái giữa 2 cửa sổ đang mở. Đây là lớp học lập trình thứ tám trong loạt lớp học lập trình đi kèm cho hội thảo về Ứng dụng web tiến bộ. Lớp học lập trình trước đây là Service Worker Includes. Đây là lớp học lập trình cuối cùng trong loạt lớp học lập trình này.

Kiến thức bạn sẽ học được

  • Thêm một worker dùng chung giữa nhiều cửa sổ đang mở
  • Sử dụng Comlink để giúp bạn dễ dàng làm việc với các worker hơn

Những điều bạn cần biết

  • JavaScript

Bạn cần có

2. Bắt đầu thiết lập

Bắt đầu bằng cách sao chép hoặc tải mã khởi đầu cần thiết để hoàn tất lớp học lập trình này:

Nếu bạn sao chép repo, hãy đảm bảo rằng bạn đang ở nhánh pwa06--working-with-workers. Tệp zip cũng chứa mã cho nhánh đó.

Cơ sở mã này yêu cầu Node.js 14 trở lên. Sau khi có mã, hãy chạy npm ci từ dòng lệnh trong thư mục mã để cài đặt tất cả các phần phụ thuộc mà bạn sẽ cần. Sau đó, hãy chạy npm start để khởi động máy chủ phát triển cho lớp học lập trình.

Tệp README.md của mã nguồn cung cấp nội dung giải thích cho tất cả các tệp được phân phối. Ngoài ra, sau đây là các tệp hiện có chính mà bạn sẽ sử dụng trong suốt lớp học lập trình này:

Tệp khoá

  • js/preview.js – Tệp JavaScript của trang xem trước
  • js/main.js – Tệp JavaScript của ứng dụng chính

3. Viết một Worker

Hiện tại, chức năng xem trước của ứng dụng web chỉ cho thấy nội dung mới nhất khi tải. Lý tưởng nhất là ứng dụng sẽ cho thấy bản xem trước trực tiếp khi người dùng nhập. Việc này đòi hỏi bạn phải biên dịch một lượng lớn dữ liệu và chuyển dữ liệu đó giữa 2 cửa sổ đang mở. Vì lý do này, chúng ta không muốn thực hiện thao tác này trên luồng chính của bất kỳ cửa sổ nào đang mở. Thay vào đó, hãy sử dụng một web worker dùng chung.

Để bắt đầu, hãy tạo một tệp js/worker.js bằng đoạn mã sau:

import { expose } from 'comlink';
import { marked } from 'marked';

class Compiler {
  state = {
    raw: '',
    compiled: '',
  };
  subscribers = [];

  async set(content) {
    this.state = {
      raw: content,
      compiled: marked(content),
    };

    await Promise.all(this.subscribers.map((s) => s(this.state)));
  }

  subscribe(cb) {
    this.subscribers.push(cb);
  }
}

const compiler = new Compiler();

onconnect = (e) => expose(compiler, e.ports[0]);

Giải thích

Mã này thiết lập một lớp có tên là Compiler, cho phép đặt nội dung và cho phép gọi các lượt đăng ký sau khi nội dung đó được biên dịch. Vì đây là một worker dùng chung, nên chỉ có một thực thể của lớp này được dùng, do đó, một thực thể mới của Compiler sẽ được khởi tạo. Sau đó, để việc tương tác với lớp này diễn ra liền mạch từ bên ngoài worker, Comlink được dùng để hiển thị thực thể trình biên dịch, cho phép chúng ta sử dụng tất cả các phương thức trên thực thể này như thể thực thể đó được khai báo trong mã bằng cách sử dụng thực thể đó. Vì đây là một worker dùng chung thay vì một worker chuyên dụng, nên worker này cần được cung cấp cho tất cả các kết nối.

4. Gửi nội dung đến Worker

Sau khi tạo worker, chúng ta cần gửi nội dung vào worker đó. Để làm như vậy, hãy cập nhật js/main.js để thực hiện những việc sau:

  • Nhập hàm xuất đã đặt tên wrap từ comlink
  • Tạo một Shared Worker mới có kiểu mô-đun tên là worker, đặt kiểu của Shared Worker này thành module và trỏ đến Shared Worker đó bằng mẫu new URL (new URL('./worker.js', import.meta.url))
  • Tạo một biến compiler wrap worker.port
  • Trong hàm cập nhật của trình chỉnh sửa (editor.onUpdate), sau khi lưu nội dung vào cơ sở dữ liệu, hãy đợi compiler.set hoàn tất, truyền nội dung vào

Giải thích

Việc bao bọc một mục xuất Comlink cho phép sử dụng những thứ như các phương thức lớp được hiển thị như thể chúng không được chia sẻ trên ranh giới của worker, ngoại trừ việc giờ đây mọi thứ đều không đồng bộ. Vì đây là một worker dùng chung thay vì một worker chuyên dụng, nên Comlink cần bao bọc cổng của worker thay vì chính worker đó. Giờ đây, bất cứ khi nào có nội dung cập nhật cho trình chỉnh sửa, nội dung đó sẽ được gửi vào worker để xử lý!

5. Cập nhật Trang xem trước

Bước cuối cùng là lấy nội dung đã biên dịch ra khỏi worker dùng chung vào bản xem trước! Quy trình thiết lập để thực hiện việc này phần lớn là giống nhau, nhưng vì các hàm không thể truyền giữa ranh giới của worker, nên bạn cần sử dụng một proxy cho hàm thay thế. Comlink luôn sẵn sàng trợ giúp. Cập nhật js/preview.js để thực hiện những việc sau:

  • Nhập các hàm xuất được đặt tên wrapproxy từ comlink
  • Tạo và bao bọc worker dùng chung như bạn đã làm trong js/main.js
  • Gọi phương thức subscribe của trình biên dịch bằng một hàm proxy đặt thuộc tính compiled của dữ liệu đến thành HTML bên trong của vùng xem trước

Sau khi hoàn tất, hãy mở bản xem trước, bắt đầu nhập trong trình chỉnh sửa và bạn sẽ thấy thú vị và hào hứng khi xem markdown tự động biên dịch và xuất hiện theo thời gian thực trong vùng xem trước mà không chặn luồng chính của trang nào!

6. Xin chúc mừng!

Bạn đã tìm hiểu cách sử dụng worker dùng chung để chia sẻ trạng thái giữa nhiều phiên bản PWA.