Để theo dõi một cách đáng tin cậy số liệu phân tích, Core Web Vitals và dữ liệu đo từ xa bao gồm toàn bộ lượt truy cập của người dùng vào một trang web (không chỉ cho đến khi tải trang), hãy sử dụng API fetchLater().
API fetchLater() là cách đáng tin cậy nhất để gửi dữ liệu đến máy chủ trong trường hợp không cần phản hồi và thời gian gửi không gấp, áp dụng cho dữ liệu như số liệu phân tích người dùng, dữ liệu đo từ xa, theo dõi lỗi và các chỉ số hiệu suất như Core Web Vitals.
Kỹ thuật cũ hơn như tạo pixel <img> trong trình nghe sự kiện unload nổi tiếng là không đáng tin cậy (đặc biệt là trên thiết bị di động) và có thể ảnh hưởng tiêu cực đến hiệu suất (bằng cách khiến các trang không đủ điều kiện sử dụng bfcache).
Cách triển khai
Lên lịch yêu cầu: Ngay khi có dữ liệu liên quan, hãy gọi
fetchLater()bằng tải trọng dữ liệu của bạn. Thao tác này sẽ đưa dữ liệu vào hàng đợi để gửi sau.Cập nhật tải trọng nếu cần: Nếu người dùng tạo thêm dữ liệu hoặc trạng thái thay đổi, hãy huỷ yêu cầu đã lên lịch trước đó và gọi lại
fetchLater()bằng ảnh chụp nhanh đã cập nhật đầy đủ.Để trình duyệt xử lý phần còn lại: Khi người dùng rời khỏi hoặc đóng thẻ, trình duyệt sẽ gửi tải trọng một cách đáng tin cậy từ lệnh gọi
fetchLater()gần đây nhất của bạn.
Mã mẫu
Mã này đo lường thời lượng phiên của một người dùng truy cập vào một trang bằng cách sử dụng fetchLater() để đưa một beacon mới vào hàng đợi sau mỗi 10 giây với thời lượng phiên được cập nhật.
const ANALYTICS_ENDPOINT = '/path/to/analytics/endpoint';
const sessionData = {
duration: 0,
id: crypto.randomUUID(),
};
let fetchLaterController = null;
function queueBeacon() {
// Abort any pending beacons before creating a new one.
if (fetchLaterController) {
fetchLaterController.abort();
}
fetchLaterController = new AbortController();
// Update session duration to the current page time.
sessionData.duration = performance.now();
// Schedule a fetch for the data payload to be sent later.
// IMPORTANT: wrap the call in a try/catch to handle quota errors.
try {
fetchLater(ANALYTICS_ENDPOINT, {
method: 'POST',
headers: {'content-type': 'application/json'},
body: JSON.stringify(sessionData),
signal: fetchLaterController.signal,
});
} catch (error) {
// Handle errors as needed.
}
}
// Update the session data and queue a new beacon every 10 seconds.
setInterval(queueBeacon, 10000);
Các phương pháp hay nhất
- NÊN sử dụng
fetchLater()để gửi dữ liệu đến máy chủ trong mọi trường hợp không cần phản hồi và không cần gửi dữ liệu ngay lập tức. - NÊN sử dụng
AbortControllerđể huỷ lệnh tìm nạp đang chờ xử lý trong trường hợp dữ liệu có thể cần được cập nhật trước khi người dùng rời khỏi trang - NÊN giảm thiểu kích thước tải trọng để tránh vượt quá hạn mức (hiện tại là khoảng 64 KB cho mỗi nguồn gốc).
- NÊN gói các lệnh gọi đến
fetchLater()trongtry/catchđể xử lý lỗi hạn mức. - NÊN phát hiện tính năng về sự hiện diện của
fetchLater()trênglobalThisvà triển khai chiến lược dự phòng cho các trình duyệt không hỗ trợ API. - KHÔNG sử dụng đối tượng
ReadableStreamcho nội dung yêu cầu vì việc này sẽ gây ra lỗi.
Hỗ trợ trình duyệt và chiến lược dự phòng
Bạn cần có chiến lược dự phòng nếu fetchLater() không đáp ứng mục tiêu Cơ sở. Tuy nhiên, do API này có độ tin cậy và hiệu suất cao hơn, nên bạn nên sử dụng fetchLater() nếu trình duyệt hỗ trợ.
Chiến lược dự phòng được đề xuất là sử dụng polyfill bên dưới. Polyfill này xử lý nội bộ các trình duyệt không hỗ trợ bằng cách sử dụng fetch() với keepalive hoặc navigator.sendBeacon(). Mã của bạn PHẢI gọi trực tiếp fetchLater() — tuyệt đối không được tự gọi fetch(), sendBeacon() hoặc các API báo hiệu khác.
fetchLater() polyfill
Sử dụng polyfill fetchLater() tối thiểu sau đây để triển khai API gần nhất có thể trong các trình duyệt không hỗ trợ.
Điểm khác biệt đáng chú ý duy nhất về hành vi của polyfill này là nó sử dụng visibilitychange để phát hiện thời điểm người dùng rời đi, thay vì dựa vào tính năng xử lý dỡ tải gốc của trình duyệt. Đây là thông tin triển khai nội bộ – mã của bạn không cần theo dõi visibilitychange hoặc bất kỳ sự kiện nào khác trong vòng đời của trang. Bạn chỉ cần gọi fetchLater() và polyfill sẽ xử lý việc phân phối.
globalThis.fetchLater ??= function fetchLater(url, init = {}) {
let timeoutHandle;
let activated = false;
function sendNow() {
if (!(init.signal && init.signal.aborted)) {
// Use fetch keepalive if the browser supports it or if custom fetch
// parameters are specified (e.g. custom headers or methods).
// Otherwise fall back to `navigator.sendBeacon()`.
if (
'keepalive' in Request.prototype ||
init.method !== 'POST' ||
init.headers
) {
fetch(url, Object.assign({}, init, {keepalive: true}));
activated = true;
} else {
activated = navigator.sendBeacon(url, init.body);
}
}
destroy();
}
function destroy() {
document.removeEventListener('visibilitychange', sendNow);
clearTimeout(timeoutHandle);
}
if (document.visibilityState === 'hidden') {
// If the beacon was created while the page is already hidden, send data
// ASAP but wait until the next microtask to allow all sync code to run.
queueMicrotask(sendNow);
} else {
document.addEventListener('visibilitychange', sendNow);
if (typeof init.activateAfter === 'number' && init.activateAfter >= 0) {
timeoutHandle = setTimeout(sendNow, init.activateAfter);
}
}
if (init.signal) {
init.signal.addEventListener('abort', destroy);
}
return {
get activated() {
return activated;
},
};
};