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ợ fetchDidFail
và fetchDidFail
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:
- Tải trang và đăng ký trình chạy dịch vụ.
- 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.
- Đư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
- 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
- Bây giờ, hãy bật mạng hoặc máy chủ web của bạn.
Buộc thực hiện một sự kiện
sync
sớm bằng cách chuyển đếnChrome DevTools > Application > Service Workers
, nhập tên thẻ củaworkbox-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á".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
-
hàm khởi tạo
void
Hàm
constructor
sẽ có dạng như sau:(name: string, options?: QueueOptions) => {...}
-
tên
string
Xem tài liệu về
workbox-background-sync.Queue
để biết thông tin chi tiết về tham số. -
tùy chọn
QueueOptions không bắt buộc
-
giá trị trả về
-
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
-
giá trị trả về
-
-
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
-
giá trị trả về
-
-
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
.
-
giá trị trả về
-
-
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:() => {...}
-
giá trị trả về
-
-
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
-
giá trị trả về
Promise<StorableRequest>
-