đồng bộ hoá nền hộp công việc

Khi bạn gửi dữ liệu đến một máy chủ web, đôi khi các yêu cầu sẽ không thực hiện được. Điều này có thể là do người dùng đã mất kết nối hoặc có thể là do máy chủ ngừng hoạt động; trong cả hai trường hợp, bạn thường muốn thử gửi lại yêu cầu sau.

APIBackgroundSync mới là một giải pháp lý tưởng cho vấn đề này. Khi phát hiện thấy một yêu cầu mạng không thành công, một trình chạy dịch vụ có thể đăng ký để nhận một sự kiện sync. Sự kiện này được phân phối khi trình duyệt cho rằng kết nối đã trở lại. Xin lưu ý rằng sự kiện đồng bộ hoá có thể được phân phối ngay cả khi người dùng đã rời khỏi ứng dụng, giúp sự kiện này hiệu quả hơn nhiều so với phương thức truyền thống để thử lại các yêu cầu không thành công.

Tính năng Đồng bộ hoá nền của hộp công việc được thiết kế nhằm giúp bạn dễ dàng sử dụng API nền tảng đồng bộ hoá và tích hợp việc sử dụng API này với các mô-đun Workbox khác. Công cụ này cũng triển khai chiến lược dự phòng cho các trình duyệt chưa triển khaiBackgroundSync.

Các trình duyệt hỗ trợ API BackgroundSync sẽ thay mặt bạn tự động phát lại các yêu cầu không thành công trong một khoảng thời gian do trình duyệt quản lý, có thể là sử dụng thuật toán thời gian đợi luỹ thừa giữa các lần thử phát lại. Trong các trình duyệt không hỗ trợ sẵn API BackgroundSync, tính năng Đồng bộ hoá nền Workbox sẽ tự động phát lại mỗi khi trình chạy dịch vụ khởi động.

Cách sử dụng cơ bản

Cách dễ nhất để sử dụng tính năng Đồng bộ hoá trong nền là sử dụng Plugin, công cụ này sẽ tự động xếp hàng các yêu cầu không thành công và thử lại khi các sự kiện sync sau này được kích hoạt.

import {BackgroundSyncPlugin} from 'workbox-background-sync';
import {registerRoute} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';

const bgSyncPlugin = new BackgroundSyncPlugin('myQueueName', {
  maxRetentionTime: 24 * 60, // Retry for max of 24 Hours (specified in minutes)
});

registerRoute(
  /\/api\/.*\/*.json/,
  new NetworkOnly({
    plugins: [bgSyncPlugin],
  }),
  'POST'
);

BackgroundSyncPlugin nối với lệnh gọi lại trình bổ trợ fetchDidFailfetchDidFail chỉ được gọi nếu có một ngoại lệ được gửi, rất có thể là do lỗi mạng. Điều này có nghĩa là hệ thống sẽ không thử lại yêu cầu nếu nhận được một phản hồi có trạng thái lỗi 4xx hoặc 5xx. Nếu muốn thử lại tất cả các yêu cầu dẫn đến, chẳng hạn như trạng thái 5xx, bạn có thể thực hiện bằng cách thêm trình bổ trợ fetchDidSucceed vào chiến lược của mình:

const statusPlugin = {
  fetchDidSucceed: ({response}) => {
    if (response.status >= 500) {
      // Throwing anything here will trigger fetchDidFail.
      throw new Error('Server error.');
    }
    // If it's not 5xx, use the response as-is.
    return response;
  },
};

// Add statusPlugin to the plugins array in your strategy.

Cách sử dụng nâng cao

Tính năng Đồng bộ hoá nền hộp công việc cũng cung cấp một lớp Queue để bạn có thể tạo thực thể và thêm các yêu cầu không thành công. Các yêu cầu không thành công sẽ được lưu trữ trong IndexedDB và được thử lại khi trình duyệt cho rằng kết nối đã được khôi phục (tức là khi nhận được sự kiện đồng bộ hoá).

Tạo hàng đợi

Để tạo Hàng đợi đồng bộ hoá nền hộp công việc, bạn cần tạo hàng đợi bằng một tên hàng đợi (phải là tên dành riêng cho nguồn gốc của bạn):

import {Queue} from 'workbox-background-sync';

const queue = new Queue('myQueueName');

Tên hàng đợi được sử dụng như một phần của tên thẻ nhận được register()-ed bởi SyncManager chung. Tên này cũng được dùng làm tên Object Store (Cửa hàng đối tượng) cho cơ sở dữ liệu IndexedDB.

Thêm yêu cầu vào Hàng đợi

Sau khi tạo thực thể Hàng đợi, bạn có thể thêm các yêu cầu không thành công vào thực thể đó. Bạn không thêm được yêu cầu bằng cách gọi phương thức .pushRequest(). Ví dụ: mã sau đây phát hiện mọi yêu cầu không thành công và thêm các yêu cầu đó vào hàng đợi:

import {Queue} from 'workbox-background-sync';

const queue = new Queue('myQueueName');

self.addEventListener('fetch', event => {
  // Add in your own criteria here to return early if this
  // isn't a request that should use background sync.
  if (event.request.method !== 'POST') {
    return;
  }

  const bgSyncLogic = async () => {
    try {
      const response = await fetch(event.request.clone());
      return response;
    } catch (error) {
      await queue.pushRequest({request: event.request});
      return error;
    }
  };

  event.respondWith(bgSyncLogic());
});

Sau khi được thêm vào hàng đợi, yêu cầu sẽ được tự động thử lại khi trình chạy dịch vụ nhận được sự kiện sync (xảy ra khi trình duyệt cho rằng kết nối đã được khôi phục). Các trình duyệt không hỗ trợ APIBackgroundSync sẽ thử lại hàng đợi này mỗi khi trình chạy dịch vụ được khởi động. Phương thức này đòi hỏi trang kiểm soát trình chạy dịch vụ phải chạy, vì vậy, hoạt động này sẽ không thực sự hiệu quả.

Kiểm thử tính năng đồng bộ hoá trong nền cho Workbox

Tiếc là việc kiểm thửBackgroundSync có phần khó trực quan và khó khăn vì một số lý do.

Để kiểm thử việc triển khai, tốt nhất bạn nên làm như sau:

  1. Tải trang và đăng ký trình chạy dịch vụ.
  2. Tắt mạng của máy tính hoặc tắt máy chủ web.
    • KHÔNG SỬ DỤNG CHROME DEVTOOLS NGOẠI TUYẾN. Hộp đánh dấu ngoại tuyến trong DevTools chỉ ảnh hưởng đến các yêu cầu từ trang. Các yêu cầu Service Worker sẽ tiếp tục được thực hiện.
  3. Đưa các yêu cầu mạng vào hàng đợi bằng tính năng Đồng bộ hoá nền Workbox.
    • Bạn có thể kiểm tra xem các yêu cầu đã được đưa vào hàng đợi bằng cách xem trong Chrome DevTools > Application > IndexedDB > workbox-background-sync > requests
  4. Bây giờ, hãy bật mạng hoặc máy chủ web của bạn.
  5. Buộc thực hiện một sự kiện sync sớm bằng cách chuyển đến Chrome DevTools > Application > Service Workers, nhập tên thẻ của workbox-background-sync:<your queue name>, trong đó <your queue name> phải là tên của hàng đợi mà bạn đặt, sau đó nhấp vào nút "Đồng bộ hoá".

    Ví dụ về nút Đồng bộ hoá trong Công cụ của Chrome cho nhà phát triển

  6. Bạn sẽ thấy các yêu cầu mạng được gửi đi cho những yêu cầu không thành công và dữ liệu IndexedDB trở nên trống vì các yêu cầu đó đã được phát lại thành công.

Loại

BackgroundSyncPlugin

Một lớp triển khai phương thức gọi lại trong vòng đời fetchDidFail. Thao tác này giúp bạn dễ dàng thêm các yêu cầu không thành công vào Hàng đợi đồng bộ hoá ở chế độ nền.

Thuộc tính

Queue

Một lớp để quản lý việc lưu trữ các yêu cầu không thành công trong IndexedDB và thử lại sau. Bạn có thể quan sát tất cả các phần của quá trình lưu trữ và phát lại thông qua lệnh gọi lại.

Thuộc tính

  • hàm khởi tạo

    void

    Tạo một thực thể của Hàng đợi có các lựa chọn cho trước

    Hàm constructor sẽ có dạng như sau:

    (name: string,options?: QueueOptions)=> {...}

    • tên

      string

      Tên duy nhất cho hàng đợi này. Tên này phải là duy nhất vì tên này dùng để đăng ký các sự kiện đồng bộ hoá và lưu trữ các yêu cầu trong IndexedDB dành riêng cho thực thể này. Hệ thống sẽ báo lỗi nếu phát hiện thấy tên trùng lặp.

    • tùy chọn

      QueueOptions không bắt buộc

  • tên

    string

  • getAll

    void

    Trả về tất cả các mục nhập chưa hết hạn (mỗi maxRetentionTime). Mọi mục nhập đã hết hạn sẽ bị xoá khỏi hàng đợi.

    Hàm getAll sẽ có dạng như sau:

    ()=> {...}

    • giá trị trả về

      Promise<QueueEntry[]>

  • popRequest

    void

    Xoá và trả về yêu cầu gần đây nhất trong hàng đợi (cùng với dấu thời gian và mọi siêu dữ liệu). Đối tượng được trả về có dạng: {request, timestamp, metadata}.

    Hàm popRequest sẽ có dạng như sau:

    ()=> {...}

    • giá trị trả về

      Promise<QueueEntry>

  • pushRequest

    void

    Lưu trữ yêu cầu đã chuyển trong IndexedDB (kèm theo dấu thời gian và mọi siêu dữ liệu) ở cuối hàng đợi.

    Hàm pushRequest sẽ có dạng như sau:

    (entry: QueueEntry)=> {...}

    • mục nhập

      QueueEntry

    • giá trị trả về

      Promise<void>

  • registerSync

    void

    Đăng ký một sự kiện đồng bộ hoá bằng một thẻ dành riêng cho trường hợp này.

    Hàm registerSync sẽ có dạng như sau:

    ()=> {...}

    • giá trị trả về

      Promise<void>

  • replayRequests

    void

    Lặp lại từng yêu cầu trong hàng đợi và cố gắng tìm nạp lại yêu cầu đó. Nếu có bất kỳ yêu cầu nào không thể tìm nạp lại, thì yêu cầu đó sẽ được đưa trở lại vị trí cũ trong hàng đợi (đăng ký một lần thử lại cho sự kiện đồng bộ hoá tiếp theo).

    Hàm replayRequests sẽ có dạng như sau:

    ()=> {...}

    • giá trị trả về

      Promise<void>

  • shiftRequest

    void

    Xoá và trả về yêu cầu đầu tiên trong hàng đợi (cùng với dấu thời gian và mọi siêu dữ liệu). Đối tượng được trả về có dạng: {request, timestamp, metadata}.

    Hàm shiftRequest sẽ có dạng như sau:

    ()=> {...}

    • giá trị trả về

      Promise<QueueEntry>

  • size

    void

    Trả về số lượng mục nhập có trong hàng đợi. Xin lưu ý rằng các mục nhập đã hết hạn (mỗi maxRetentionTime) cũng được tính vào số lượng này.

    Hàm size sẽ có dạng như sau:

    ()=> {...}

    • giá trị trả về

      Hứa hẹn<number>

  • unshiftRequest

    void

    Lưu trữ yêu cầu đã chuyển trong IndexedDB (kèm theo dấu thời gian và mọi siêu dữ liệu) ở đầu hàng đợi.

    Hàm unshiftRequest sẽ có dạng như sau:

    (entry: QueueEntry)=> {...}

    • mục nhập

      QueueEntry

    • giá trị trả về

      Promise<void>

QueueOptions

Thuộc tính

  • forceSyncFallback

    boolean không bắt buộc

  • maxRetentionTime

    số không bắt buộc

  • onSync

    OnSyncCallback không bắt buộc

QueueStore

Một lớp để quản lý việc lưu trữ các yêu cầu từ Hàng đợi trong IndexedDB, được lập chỉ mục theo tên hàng đợi để truy cập dễ dàng hơn.

Hầu hết các nhà phát triển sẽ không cần truy cập trực tiếp vào lớp này; lớp này dành cho các trường hợp sử dụng nâng cao.

Thuộc tính

  • hàm khởi tạo

    void

    Liên kết thực thể này với một thực thể Hàng đợi để có thể xác định các mục đã thêm theo tên hàng đợi.

    Hàm constructor sẽ có dạng như sau:

    (queueName: string)=> {...}

    • queueName

      string

  • deleteEntry

    void

    Xoá mục nhập của mã nhận dạng đã cho.

    CẢNH BÁO: phương thức này không đảm bảo mục đã xoá sẽ thuộc về hàng đợi này (tức là khớp với queueName). Tuy nhiên, giới hạn này có thể chấp nhận được vì lớp này không được hiển thị công khai. Một bước kiểm tra bổ sung sẽ khiến phương thức này chạy chậm hơn mức cần thiết.

    Hàm deleteEntry sẽ có dạng như sau:

    (id: number)=> {...}

    • id

      number

    • giá trị trả về

      Promise<void>

  • getAll

    void

    Trả về tất cả mục nhập trong cửa hàng khớp với queueName.

    Hàm getAll sẽ có dạng như sau:

    ()=> {...}

    • giá trị trả về

      Promise<QueueStoreEntry[]>

  • popEntry

    void

    Xoá và trả về mục nhập cuối cùng trong hàng đợi khớp với queueName.

    Hàm popEntry sẽ có dạng như sau:

    ()=> {...}

    • giá trị trả về

      Promise<QueueStoreEntry>

  • pushEntry

    void

    Thêm một mục cuối cùng vào hàng đợi.

    Hàm pushEntry sẽ có dạng như sau:

    (entry: UnidentifiedQueueStoreEntry)=> {...}

    • mục nhập

      UnidentifiedQueueStoreEntry

    • giá trị trả về

      Promise<void>

  • shiftEntry

    void

    Xoá và trả về mục nhập đầu tiên trong hàng đợi khớp với queueName.

    Hàm shiftEntry sẽ có dạng như sau:

    ()=> {...}

    • giá trị trả về

      Promise<QueueStoreEntry>

  • size

    void

    Trả về số lượng mục nhập trong cửa hàng khớp với queueName.

    Hàm size sẽ có dạng như sau:

    ()=> {...}

    • giá trị trả về

      Hứa hẹn<number>

  • unshiftEntry

    void

    Thêm mục nhập trước trong hàng đợi.

    Hàm unshiftEntry sẽ có dạng như sau:

    (entry: UnidentifiedQueueStoreEntry)=> {...}

    • mục nhập

      UnidentifiedQueueStoreEntry

    • giá trị trả về

      Promise<void>

StorableRequest

Một lớp giúp dễ dàng chuyển đổi tuần tự và giải tuần tự các yêu cầu để các yêu cầu đó có thể được lưu trữ trong IndexedDB.

Hầu hết các nhà phát triển sẽ không cần truy cập trực tiếp vào lớp này; lớp này dành cho các trường hợp sử dụng nâng cao.

Thuộc tính

  • hàm khởi tạo

    void

    Chấp nhận một đối tượng dữ liệu yêu cầu có thể dùng để tạo Request nhưng cũng có thể được lưu trữ trong IndexedDB.

    Hàm constructor sẽ có dạng như sau:

    (requestData: RequestData)=> {...}

    • requestData

      RequestData

      Đối tượng dữ liệu yêu cầu bao gồm url cùng với mọi thuộc tính có liên quan của [requestInit]https://fetch.spec.whatwg.org/#requestinit.

  • sao chép

    void

    Tạo và trả về một bản sao sâu của thực thể.

    Hàm clone sẽ có dạng như sau:

    ()=> {...}

  • toObject

    void

    Trả về bản sao sâu của các thực thể _requestData.

    Hàm toObject sẽ có dạng như sau:

    ()=> {...}

    • giá trị trả về

      RequestData

  • toRequest

    void

    Chuyển đổi thực thể này thành một Yêu cầu.

    Hàm toRequest sẽ có dạng như sau:

    ()=> {...}

    • giá trị trả về

      Yêu cầu

  • fromRequest

    void

    Chuyển đổi đối tượng Yêu cầu thành một đối tượng thuần tuý có thể được sao chép có cấu trúc hoặc chuỗi JSON.

    Hàm fromRequest sẽ có dạng như sau:

    (request: Request)=> {...}

    • request

      Yêu cầu