تكون معظم بيانات الإحصاءات والقياس عن بُعد وCore Web Vitals ذات أولوية أقل من الاستجابة للمستخدم، لذا يمكنك تأجيل إرسالها بأمان إلى أن يغادر المستخدم الصفحة. ويُستثنى من ذلك إذا كنت بحاجة إلى تقديم تعديلات في الوقت الفعلي، وفي هذه الحالة تكون حداثة المحتوى مهمة.
الطريقة المثلى لتقديم تحديثات الإحصاءات في الوقت الفعلي، مع تقليل عدد الإشارات، هي استخدام fetchLater() مع خيار الإعداد activateAfter. يتيح لك ذلك تجميع كل أحداث الإحصاءات التي تحدث خلال فترة زمنية معيّنة في إشارة واحدة، والتي يتم إرسالها بشكل موثوق حتى إذا غادر المستخدم الصفحة قبل انتهاء المهلة.
كيفية الإعداد
جدولة الطلب: فور توفّر أي بيانات إحصاءات ذات صلة، يمكنك استدعاء
fetchLater()مع حمولة البيانات وتمرير قيمةactivateAfter. يؤدي ذلك إلى وضع البيانات في قائمة انتظار ليتم إرسالها بعد مرور هذه المدة الزمنية، أو إذا غادر المستخدم الصفحة قبل ذلك.تجميع أحداث متعددة معًا: إذا حدث حدث إحصاءات جديد قبل انتهاء مهلة
activateAfter، يمكنك إلغاء الطلب المُجدوَل سابقًا واستدعاءfetchLater()مرة أخرى (باستخدام قيمةactivateAfterنفسها) مع قائمة انتظار الأحداث الكاملة في حمولة واحدة.إعادة ضبط قائمة انتظار الأحداث عند انتهاء المهلة: في حال وقوع حدث جديد في "إحصاءات Google" بعد إرسال الإشارة المجدوَلة بنجاح (أي أنّ قيمة
activatedلنتيجةfetchLater()هيtrue)، أعِد ضبط قائمة انتظار الأحداث.السماح للمتصفّح بمعالجة بقية البيانات: إذا غادر المستخدم الصفحة أو أغلق علامة التبويب قبل انتهاء مهلة
activateAfter، سيواصل المتصفّح إرسال الحمولة من أحدث طلبfetchLater()بشكل موثوق.
مثال على الرمز
يتتبّع هذا الرمز جميع أحداث load وclick على الصفحة، ويجمع معًا جميع الأحداث التي تقع خلال مهلة 10 ثوانٍ.
// Replace with your analytics endpoint.
const ANALYTICS_ENDPOINT = '/path/to/analytics/endpoint';
// Replace with a time window of your choice. All analytics events that
// occur within this time window will be batched together.
const BATCH_WINDOW = 10 * 1000;
// The maximum number of events to batch. Pick a number that is unlikely
// to overflow the fetchLater() quota for the page.
const MAX_QUEUE_SIZE = 100;
const eventQueue = [];
let fetchLaterResult;
let fetchLaterController;
function trackEvent(eventData) {
// If the previously queued beacon has already been sent, or if the
// max queue size has been met, reset the queue.
if (fetchLaterResult?.activated || eventQueue.length > MAX_QUEUE_SIZE) {
fetchLaterController = null;
fetchLaterResult = null;
eventQueue.length = 0;
}
eventQueue.push(eventData);
// Abort any pending beacons before creating a new one.
if (fetchLaterController) {
fetchLaterController.abort();
}
fetchLaterController = new AbortController();
// Schedule a fetch for the events to be sent when the batch window expires.
// IMPORTANT: wrap the call in a try/catch to handle quota errors.
try {
fetchLaterResult = fetchLater(ANALYTICS_ENDPOINT, {
method: 'POST',
headers: {'content-type': 'application/json'},
body: JSON.stringify(eventQueue),
signal: fetchLaterController.signal,
activateAfter: BATCH_WINDOW,
});
} catch (error) {
// Handle errors as needed.
}
}
// Track page loads.
window.addEventListener('load', () => {
trackEvent({type: 'page_load'});
});
// Track click events.
window.addEventListener('click', (event) => {
trackEvent({type: 'click', target: serializeElement(event.target)});
});
أفضل الممارسات
- يجب استخدام
fetchLater()مع ضبط الخيارactivateAfterلتجميع أحداث إحصاءات متعددة تحدث بالقرب من بعضها. - يجب استخدام
AbortControllerلإلغاء عملية الجلب في انتظار المراجعة في الحالات التي يقع فيها حدث إحصاءات جديد. - يجب التأكّد من عدم تجميع عدد كبير جدًا من الأحداث معًا وتجاوز حصة
fetchLater()(حاليًا تبلغ 64 كيلوبايت تقريبًا لكل مصدر). - يجب تضمين طلبات
fetchLater()فيtry/catchلمعالجة الأخطاء المتعلقة بالحصص. - يجب رصد توفّر
fetchLater()علىglobalThisوتنفيذ استراتيجية احتياطية للمتصفّحات التي لا تتوافق مع واجهة برمجة التطبيقات. - لا تستخدِم عنصر
ReadableStreamلنص الطلب، لأنّ ذلك سيؤدي إلى حدوث خطأ.
توافق المتصفّح واستراتيجيات الاحتياط
لذلك، عادةً ما تكون هناك حاجة إلى استراتيجية احتياطية.
ومع ذلك، نظرًا إلى الموثوقية المحسّنة ومزايا الأداء التي توفّرها واجهة برمجة التطبيقات هذه، يجب استخدام fetchLater() إذا كان المتصفّح يتيح ذلك.
fetchLater() polyfill
استخدِم رمز polyfill التالي للسمة fetchLater()، والذي ينفّذ واجهة برمجة التطبيقات بأقرب شكل ممكن في المتصفّحات غير المتوافقة.
يتمثّل الاختلاف الوحيد الملحوظ في السلوك مع هذا الـ polyfill في أنّه بدلاً من إرسال الحمولة عندما يغادر المستخدم الصفحة، يتم إرسالها عندما تتغيّر حالة visibilityState للصفحة إلى "مخفية"، لأنّ هذه هي إشارة نهاية الجلسة الأكثر موثوقية والمتاحة على نطاق واسع اليوم.
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;
},
};
};