من الشائع أن تحتاج صفحات الويب إلى إرسال البيانات (أو "الإشارة") مرة أخرى إلى خادمها، مثل بيانات الإحصاءات لجلسة المستخدِم الحالية. بالنسبة إلى المطوّرين، يتطلّب ذلك موازنة بين خفض الطلبات المستمرة والمتكرّرة في بعض الأحيان بدون المخاطرة بفقدان البيانات في حال إغلاق علامة التبويب أو انتقال المستخدم إلى صفحة أخرى قبل إرسال إشارة.
في العادة، كان المطوّرون يستخدِمون حدثَي pagehide
وvisibilitychange
لرصد الصفحة أثناء تفريغها، ثم يستخدِمون navigator.sendBeacon()
أو fetch()
مع keepalive
لعرض بيانات ال beacon. ومع ذلك، يتضمّن كلا الحدثَين حالات صعبة تختلف استنادًا إلى متصفّح المستخدِم، وفي بعض الأحيان لا تصل الأحداث مطلقًا، خاصةً على الأجهزة الجوّالة.
نقترح استخدام fetchLater()
لاستبدال هذا التعقيد بطلب بيانات واحد من واجهة برمجة التطبيقات. ويعمل هذا الإجراء على النحو الذي يوحي به اسمه تمامًا: فهو يطلب من المتصفّح التأكّد من إرسال طلب في وقت ما في المستقبل، حتى إذا تم إغلاق الصفحة أو غادر المستخدم الصفحة.
يتوفّر fetchLater()
في Chrome للاختبار من خلال مستخدمين حقيقيين لديهم فترة تجريبية أصلية بدءًا من الإصدار 121 (الذي تم طرحه في كانون الثاني/يناير 2024)، ويستمر حتى 3 أيلول (سبتمبر) 2024.
واجهة برمجة التطبيقات fetchLater()
const fetchLaterResult = fetchLater(request, options);
تأخذ الدالة fetchLater()
وسيطتين، وهما متطابقتان بشكل عام مع وسيطات fetch()
:
- العنصر
request
، إما عنوان URL لسلسلة أو مثيلRequest
- عنصر
options
اختياري، يمدّدoptions
منfetch()
باستخدام مهلة تُعرف باسمactivateAfter
.
يعرض fetchLater()
FetchLaterResult
يحتوي حاليًا على خاصيّة واحدة للقراءة فقط activated
، والتي سيتم ضبطها على true
بعد انقضاء الوقت المحدّد وإجراء عملية الجلب. يتم تجاهل أي ردّ على طلب "fetchLater()
".
request
أبسط استخدام هو عنوان URL بحد ذاته:
fetchLater('/endpoint/');
ولكن، تمامًا مثل fetch()
، يمكن ضبط عدد كبير من الخيارات في طلب fetchLater()
، بما في ذلك العناوين المخصّصة وسلوك بيانات الاعتماد ونص POST
وAbortController
signal
لإلغائه على الأرجح.
fetchLater('/endpoint/', {
method: 'GET',
cache: 'no-store',
mode: 'same-origin',
headers: {Authorization: 'SUPER_SECRET'},
});
options
يُوسّع عنصر الخيارات خيارات fetch()
باستخدام مهلة، activateAfter
، في حال أردت تشغيل الطلب بعد المهلة أو عند إزالة تحميل الصفحة، أيّهما يحدث أولاً.
يتيح لك ذلك تحديد المفاضلة بين الحصول على البيانات في آخر لحظة ممكنة أو عندما تكون في الوقت المناسب.
على سبيل المثال، إذا كان لديك تطبيق يتركه المستخدمون عادةً مفتوحًا طوال يوم العمل، قد تحتاج إلى ضبط مهلة مدتها ساعة لضمان إحصاءات أكثر دقة مع ضمان إرسال إشارات إذا خرج المستخدم في أي وقت قبل انقضاء هذه الساعة. يمكن بعد ذلك إعداد fetchLater()
جديد للساعة التالية من الإحصاءات.
const hourInMilliseconds = 60 * 60 * 1000;
fetchLater('/endpoint/', {activateAfter: hourInMilliseconds});
مثال على الاستخدام
من المشاكل التي تواجهك عند قياس مؤشرات أداء الويب الأساسية في الميدان أنّ أيًا من مقاييس الأداء قد يتغيّر إلى أن يغادر المستخدم الصفحة فعليًا. على سبيل المثال، يمكن أن تحدث تغييرات أكبر في التصميم في أي وقت، أو يمكن أن تستغرق الصفحة وقتًا أطول للردّ على تفاعل.
ومع ذلك، لا تريد المخاطرة بفقدان جميع بيانات الأداء بسبب إشارات Beacon غير المكتملة أو التي تتضمّن أخطاء عند إزالة الصفحة من الذاكرة. وهو مرشح مثالي لـ fetchLater()
.
في هذا المثال، يتم استخدام مكتبة web-vitals.js لمراقبة المقاييس، ويتم استخدام fetchLater()
للإبلاغ عن النتائج إلى نقطة نهاية إحصاءات:
import {onCLS, onINP, onLCP} from 'web-vitals';
const queue = new Set();
let fetchLaterController;
let fetchLaterResult;
function updateQueue(metricUpdate) {
// If there was an already complete request for whatever
// reason, clear out the queue of already-sent updates.
if (fetchLaterResult?.activated) {
queue.clear();
}
queue.add(metricUpdate);
// JSON.stringify used here for simplicity and will likely include
// more data than you need. Replace with a preferred serialization.
const body = JSON.stringify([...queue]);
// Abort any existing `fetchLater()` and schedule a new one with
// the update included.
fetchLaterController?.abort();
fetchLaterController = new AbortController();
fetchLaterResult = fetchLater('/analytics', {
method: 'POST',
body,
signal: fetchLaterController.signal,
activateAfter: 60 * 60 * 1000, // Timeout to ensure timeliness.
});
}
onCLS(updateQueue);
onINP(updateQueue);
onLCP(updateQueue);
وفي كل مرة يتم فيها تعديل أحد المقاييس، يتم إلغاء أي fetchLater()
مُجدوَل حالي باستخدام AbortController
، ويتم إنشاء fetchLater()
جديدة مع تضمين هذا التعديل.
تجربة "fetchLater()
"
كما هو موضّح، تتوفّر fetchLater()
في فترة تجريبية للمصدر حتى Chrome 126. اطّلِع على مقالة البدء في استخدام تجارب المصدر للحصول على معلومات أساسية عن تجارب المصدر.
لأغراض الاختبار المحلي، يمكن تفعيل fetchLater
باستخدام علامة ميزات "منصة الويب التجريبية" التجريبية على chrome://flags/#enable-experimental-web-platform-features
. ويمكن تفعيل هذه السياسة أيضًا من خلال تشغيل Chrome من سطر الأوامر باستخدام --enable-experimental-web-platform-features
أو علامة --enable-features=FetchLaterAPI
الأكثر استهدافًا.
إذا كنت تستخدمها في صفحة عامة، تأكَّد من رصدها من خلال التحقّق مما إذا كانت السمة fetchLater
الشاملة محدّدة قبل استخدامها:
if (globalThis.fetchLater) {
// Set up beaconing using fetchLater().
// ...
}
ملاحظات
ملاحظات المطوّرين ضرورية للحصول على واجهات برمجة تطبيقات جديدة للويب بشكل صحيح، لذا يُرجى إبلاغنا بالمشاكل والملاحظات على GitHub.