يُعدّ تحديد ما إذا تم تحميل صفحة في البداية في الخلفية (على سبيل المثال، تم فتحها في علامة تبويب جديدة في الخلفية) أمرًا بالغ الأهمية لمراقبة الأداء بدقة. غالبًا ما يتم تأخير عرض الصفحات التي يتم تحميلها في الخلفية وتكون أوقات المقاييس أطول (مثل سرعة عرض أول محتوى مرئي). يتيح لك تحديد هذه الصفحات استبعادها من تحليلات الأداء لتجنُّب البيانات المنحرفة.
الطريقة الأكثر دقة لقياس ذلك هي استخدام واجهة برمجة التطبيقات VisibilityStateEntry التي تسجّل بشكل موثوق تغييرات مستوى الرؤية في المخطط الزمني لأداء المتصفّح، بغض النظر عن وقت تنفيذ النص البرمجي فعليًا.
رصد وقت الظهور الأولي ووقت التشغيل في الخلفية
ملاحظة إلزامية: يجب استخدام performance.getEntriesByType('visibility-state') للوصول إلى سجلّ مستوى العرض الدقيق. لا تعتمد فقط على التحقّق من document.visibilityState في وقت التنفيذ، لأنّه عرضة لحالات السباق.
/**
* Accurately determines visibility state history using the Performance API.
*/
function getVisibilityInfo() {
// Retrieve VisibilityStateEntry members:
const entries = performance.getEntriesByType('visibility-state');
if (entries.length > 0) {
const firstEntry = entries[0];
// If the first performance entry for visibility is 'hidden',
// the page was loaded in the background.
const initiallyBackgrounded = firstEntry.name === 'hidden';
// Find the precise, high-resolution timestamp of when the page
// was first backgrounded.
let timeBackgrounded = null;
for (const entry of entries) {
if (entry.name === 'hidden') {
// entry.startTime is used because it provides the exact browser
// timestamp of the visibility change, which is required for precision
timeBackgrounded = entry.startTime;
break;
}
}
return {
initiallyBackgrounded,
timeBackgrounded
};
}
}
استراتيجيات احتياطية
بالنسبة إلى البيئات غير المتوافقة، يمكنك الرجوع إلى التحقّق من السمة document.visibilityState أو الاستماع إلى الحدث visibilitychange.
إلزامي: يجب أن تفهم أنّ هذا النهج الاحتياطي غالبًا ما يكون غير دقيق للغاية لتحديد حالة الخلفية الأولية. بما أنّه يمكن تحميل النصوص البرمجية وتنفيذها بشكل غير متزامن، يمكن فتح صفحة في علامة تبويب في الخلفية ثم نقلها إلى المقدّمة من قِبل المستخدم قبل انتهاء تنزيل النص البرمجي وتنفيذه. عندما يتم تشغيل النص البرمجي أخيرًا، ستتم قراءة document.visibilityState بشكل متزامن على أنّه 'visible'، وستفترض بشكل غير صحيح أنّه تم تحميل الصفحة في المقدّمة، ما يؤدي إلى عدم رصد حالتها المخفية الأولية تمامًا. علاوةً على ذلك، يفتقر الطابع الزمني الاحتياطي إلى الدقة الداخلية لواجهة Performance API. إذا كانت الدقة ذات أولوية عالية، لا تستخدِم الإجراء الاحتياطي.
/**
* Fallback implementation using document.visibilityState.
* This approach is prone to race conditions if the script loads asynchronously.
*/
function getFallbackVisibilityInfo() {
// Check the state exactly when this script executes.
// This will fail to detect an initial background state if the user
// foregrounded the page before this script executed.
let initiallyBackgrounded = document.visibilityState === 'hidden';
// If it's hidden now, we approximate that it was hidden from load (time 0).
let timeBackgrounded = initiallyBackgrounded ? 0 : null;
// Listen for future visibility changes to capture if it is backgrounded later.
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden' && timeBackgrounded === null) {
// performance.now() is used here as a fallback, but it only gives
// us the time the event listener fired, not the precise internal
// browser time the visibility actually changed.
timeBackgrounded = performance.now();
}
});
return {
get initiallyBackgrounded() { return initiallyBackgrounded; },
get timeBackgrounded() { return timeBackgrounded; }
};
}
// Modern implementation using VisibilityStateEntry API.
function getVisibilityInfo() {
// Code omitted here would be the same modern
// implementation shown earlier in this guide
// ...
}
// DO: Detect if the VisibilityStateEntry API is available
if ('VisibilityStateEntry' in window) {
// DO: If VisibilityStateEntry is available, use it first:
getVisibilityInfo();
} else {
// DO: If VisibilityStateEntry is unavailable, fall back to `document.visibilityState`:
getFallbackVisibilityInfo();
}