ميزة "التخزين المؤقت للصفحات" (أو bfcache) هي أداة تحسين للمتصفّح والتي تفعّل إمكانية الانتقال الفوري للأمام أو للخلف. إنّه يحسّن تجربة التصفح بشكل كبير، خاصةً للمستخدمين الذين لديهم شبكات أو أجهزة أبطأ.
وبصفتك مطوّر ويب، من المهم معرفة كيفية تحسين صفحاتك لاستخدام ذاكرة التخزين المؤقت bfcache، حتى يستفيد المستخدمون من مزاياها.
توافُق المتصفح
تتضمّن جميع المتصفّحات الرئيسية ذاكرة تخزين مؤقت للصور، بما في ذلك Chrome منذ الإصدار 96 وFirefox وSafari.
أساسيات ميزة "التخزين المؤقت للصفحات"
باستخدام ميزة "التخزين المؤقت للصفحات" (bfcache)، بدلاً من حذف الصفحة عندما ينتقل المستخدم بعيدًا عنها، نؤجل عملية الحذف ونوقف تنفيذ JavaScript مؤقتًا. إذا عاد المستخدم إلى الصفحة قريبًا، سنجعل الصفحة مرئية مرة أخرى ونوقف مؤقتًا تنفيذ JavaScript. ويؤدي ذلك إلى تنقّل المستخدم في الصفحة بشكل شبه فوري.
كم مرة زرت موقعًا إلكترونيًا وانقرت على رابط للانتقال إلى صفحة أخرى، ثمّ لاحظت أنّها ليست الصفحة التي تريدها، فضغطت على زر الرجوع؟ في هذه الحالة، يمكن أن تُحدث ذاكرة التخزين المؤقت للصفحات (bfcache) فرقًا كبيرًا في سرعة تحميل الصفحة السابقة:
بدون تفعيل ميزة "التخزين المؤقت للصفحات" | يتمّ بدء طلب جديد لتحميل الصفحة السابقة، وبناءً على مدى تحسين هذه الصفحة للزيارات المتكرّرة، قد يحتاج المتصفّح إلى إعادة تنزيل بعض (أو كلّ) الموارد التي تم تنزيلها للتو وإعادة تحليلها وإعادة تنفيذها. |
مع تفعيل ميزة "التخزين المؤقت للصفحات" | يكون تحميل الصفحة السابقة فوريًا بشكل أساسي، لأنّه يمكن استعادة الصفحة بأكملها من الذاكرة بدون الحاجة إلى الاتصال بالشبكة على الإطلاق. |
اطلع على هذا الفيديو عن bfcache أثناء التنفيذ لفهم السرعة التي يمكن أن تقدمها في عمليات التنقل:
في الفيديو، يكون المثال الذي يستخدم bfcache أسرع بكثير من المثال الذي لا يستخدمه.
لا يؤدي bfcache إلى تسريع التنقّل فحسب، بل يقلل أيضًا من استخدام البيانات، لأنّه لا يلزم تنزيل الموارد مرة أخرى.
توضِّح بيانات استخدام Chrome أنّ عملية واحدة من كل 10 عمليات تنقُّل على أجهزة الكمبيوتر المكتبي وعملية واحدة من كل 5 عمليات تتم على الأجهزة الجوّالة يتم إرجاعها أو إعادة توجيهها. عند تفعيل ذاكرة التخزين المؤقت bfcache، يمكن للمتصفّحات إزالة نقل البيانات والوقت الذي يتمّ إنفاقه في تحميل مليارات صفحات الويب كلّ يوم.
آلية عمل "ذاكرة التخزين المؤقت"
تختلف "ذاكرة التخزين المؤقت" التي تستخدمها ميزة bfcache عن ذاكرة التخزين المؤقت لبروتوكول HTTP، التي تؤدي دورها في تسريع عمليات التنقّل المتكرّرة. وذاكرة التخزين المؤقت للصفحات (bfcache) هي لقطة شاشة للصفحة بأكملها في الذاكرة، بما في ذلك ذاكرة JavaScript، في حين لا تحتوي ذاكرة التخزين المؤقت لبروتوكول HTTP إلا على الردود للطلبات التي تم إجراؤها سابقًا. بما أنّه من النادر جدًا أن يتم استيفاء جميع الطلبات المطلوبة لتحميل صفحة من ذاكرة التخزين المؤقت لبروتوكول HTTP، تكون الزيارات المتكرّرة باستخدام عمليات استعادة ذاكرة التخزين المؤقت للصفحات أسرع دائمًا من عمليات التنقّل غير المستندة إلى ذاكرة التخزين المؤقت للصفحات، حتى تلك التي تم تحسينها بشكل جيد.
ينطوي تجميد الصفحة لإمكانية إعادة تفعيلها مرة أخرى في وقت لاحق على بعض التعقيدات في ما يتعلق بأفضل طريقة للحفاظ على الرمز البرمجي قيد التقدم. على سبيل المثال، كيف يمكنك التعامل مع طلبات "setTimeout()
" التي تم فيها انتهاء المهلة المحددة عندما تكون الصفحة في ذاكرة التخزين المؤقت؟
الإجابة هي أنّ المتصفّحات تُوقِف مؤقتًا أيّ أدوات ضبط وقت أو وعد غير محسَّن للصفحات في bfcache، بما في ذلك جميع المهام التي لا تزال قيد المراجعة تقريبًا في قوائم انتظار مهام JavaScript، وتستأنف معالجة المهام في حال استعادة الصفحة من bfcache.
في بعض الحالات، مثل حالات انتهاء المهلة والوعود، يكون هذا الأمر منخفضًا إلى حدّ ما، ولكنه قد يؤدي في حالات أخرى إلى سلوك مربك أو غير متوقّع. على سبيل المثال، إذا أوقف المتصفح مؤقتًا مهمة مطلوبة كجزء من معاملة IndexedDB ، يمكن أن يؤثر ذلك في علامات التبويب المفتوحة الأخرى في المصدر نفسه، لأنّه يمكن الوصول إلى قواعد بيانات IndexedDB نفسها من خلال علامات تبويب متعددة في الوقت نفسه. ونتيجة لذلك، لن تحاول المتصفحات بشكل عام تخزين الصفحات مؤقتًا في منتصف معاملة IndexedDB أو أثناء استخدام واجهات برمجة تطبيقات قد تؤثر على صفحات أخرى.
لمزيد من التفاصيل عن مدى تأثير الاستخدامات المختلفة لواجهة برمجة التطبيقات في أهلية استخدام ميزة "التخزين المؤقت للصفحات" في إحدى الصفحات، يمكنك الاطّلاع على تحسين صفحاتك لاستخدام ميزة "التخزين المؤقت للصفحات".
ميزة "التخزين المؤقت للصفحات" وإطارات iframe
إذا كانت الصفحة تحتوي على أطر iframe مضمّنة، تكون أطر iframe نفسها غير مؤهَّلة لاستخدام ميزة "التخزين المؤقت للصفحات". على سبيل المثال، إذا انتقلت إلى صفحة أخرى داخل إطار iframe، ثم عدت إلى الصفحة السابقة، سينتقل المتصفح إلى "الرجوع" ضمن إطار iframe بدلاً من الانتقال إلى الإطار الرئيسي، ولكن لن تستخدِم ميزة الانتقال إلى الخلف ضمن إطار iframe ميزة bfcache.
يمكن أيضًا حظر الإطار الرئيسي من استخدام ميزة "التخزين المؤقت للصفحات" إذا كان إطار iframe مضمّنًا يستخدم واجهات برمجة تطبيقات تحظر ذلك. يمكن استخدام سياسة الأذونات التي تم ضبطها على الإطار الرئيسي أو استخدام سمات sandbox
لتجنُّب ذلك.
ميزة "التخزين المؤقت للصفحات" وتطبيقات الصفحة الواحدة (SPA)
لا تعمل ميزة bfcache مع عمليات التنقّل التي يديرها المتصفّح، لذا فهي لا تعمل مع "عمليات التنقّل البسيطة" في تطبيق من صفحة واحدة (SPA). ومع ذلك، لا يزال بإمكان ذاكرة التخزين المؤقت bfcache المساعدة عند الرجوع إلى تطبيق متعدّد الصفحات بدلاً من إعادة بدء هذا التطبيق بالكامل من البداية.
واجهات برمجة التطبيقات لمراقبة ميزة "التخزين المؤقت للصفحات"
على الرغم من أنّ ذاكرة التخزين المؤقت bfcache هي عملية تحسين تُجريها المتصفّحات تلقائيًا، لا يزال من المهم أن يعرف المطوّرون متى يحدث ذلك حتى يتمكّنوا من تحسين صفحاتهم وفقًا لذلك وتعديل أي مقاييس أو قياسات للأداء وفقًا لذلك.
الأحداث الأساسية المستخدَمة لمراقبة bfcache هي أحداث انتقال الصفحة pageshow
وpagehide
، والتي تتوافق مع معظم المتصفّحات.
يتم أيضًا إرسال أحداث رحلة المستخدِم على الصفحة الأحدث، freeze
وresume
، عندما تدخل الصفحات إلى ذاكرة التخزين المؤقت في الخلفية أو تغادرها، بالإضافة إلى بعض الحالات الأخرى، على سبيل المثال، عندما يتم تجميد علامة تبويب في الخلفية للحدّ من استخدام وحدة المعالجة المركزية. لا تتوفّر هذه الأحداث إلّا في المتصفّحات المستندة إلى Chromium.
مراقبة الحالات التي تتم فيها استعادة صفحة من bfcache
يتمّ تشغيل الحدث pageshow
مباشرةً بعد الحدث load
عند تحميل الصفحة في البداية وفي أيّ وقت تتمّ فيه استعادة الصفحة من bfcache. يحتوي الحدث pageshow
على سمة persisted
، وهي true
إذا تمت استعادة الصفحة من ذاكرة التخزين المؤقت للصفحات (bfcache) وfalse
في غير ذلك. يمكنك استخدام السمة persisted
للتمييز بين عمليات تحميل الصفحات العادية وعمليات استعادة bfcache. على سبيل المثال:
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
console.log('This page was restored from the bfcache.');
} else {
console.log('This page was loaded normally.');
}
});
في المتصفّحات التي تتيح استخدام Page Lifecycle API، يتمّ تشغيل الحدث resume
عند استعادة الصفحات من bfcache (قبل الحدث pageshow
مباشرةً) وعند إعادة زيارة المستخدِم لعلامة تبويب مُجمّدة في الخلفية. إذا أردت تعديل حالة صفحة بعد تجميدها (بما في ذلك الصفحات في ذاكرة التخزين المؤقت لصفحات الويب التي تمّت تصفّحها)، يمكنك استخدام الحدث resume
، ولكن إذا أردت قياس معدّل مرّات الوصول إلى ذاكرة التخزين المؤقت لصفحات الويب التي تمّت تصفّحها في موقعك الإلكتروني، عليك استخدام الحدث pageshow
. في بعض الحالات، قد تحتاج إلى استخدام كليهما.
للاطّلاع على تفاصيل عن أفضل الممارسات المتعلّقة بقياس ميزة "التخزين المؤقت للصفحات"، يُرجى الاطّلاع على المقالة تأثير ميزة "التخزين المؤقت للصفحات" في الإحصاءات وقياس الأداء.
مراقبة الحالات التي تدخل فيها الصفحة إلى bfcache
يتمّ تشغيل الحدث pagehide
إمّا عند إلغاء تحميل صفحة أو عندما يحاول المتصفّح وضعها في ذاكرة التخزين المؤقت bfcache.
يتضمّن الحدث pagehide
أيضًا سمة persisted
. إذا كان الرمز false
، يمكنك التأكّد من أنّ هذه الصفحة لن تدخل إلى ذاكرة التخزين المؤقت للصفحات (bfcache). ومع ذلك، لا يضمن أنّ persisted
تكون true
أنّه سيتم تخزين الصفحة مؤقتًا. يعني ذلك أنّ المتصفّح ينوي تخزين الصفحة مؤقتًا، ولكن قد تكون هناك عوامل أخرى تجعل تخزينها مؤقتًا مستحيلًا.
window.addEventListener('pagehide', (event) => {
if (event.persisted) {
console.log('This page *might* be entering the bfcache.');
} else {
console.log('This page will unload normally and be discarded.');
}
});
وبالمثل، يتم تنشيط حدث freeze
مباشرةً بعد حدث pagehide
إذا كانت قيمة persisted
هي true
، ولكن هذا يعني فقط أنّ المتصفّح ينطوي على تخزين الصفحة مؤقتًا. وقد يضطر محرّك بحث Google إلى تجاهلها لعدد من الأسباب الموضّحة لاحقًا.
تحسين صفحاتك لميزة "التخزين المؤقت للصفحات"
لا يتم تخزين جميع الصفحات في bfcache، وحتى في حال تخزين صفحة، لن تبقى هناك إلى أجل غير مسمى. من المهم أن يفهم المطوّرون ما يجعل الصفحات مؤهّلة (أو غير مؤهّلة) لاستخدام bfcache لزيادة معدّلات الوصول إلى ذاكرة التخزين المؤقت إلى أقصى حدّ.
توضّح الأقسام التالية أفضل الممارسات لزيادة احتمالية تخزين المتصفّح لصفحاتك في ذاكرة التخزين المؤقت.
عدم استخدام الحدث unload
مطلقًا
إنّ أهم طريقة لتحسين الأداء في bfcache في جميع المتصفّحات هي عدم استخدام الحدث unload
مطلقًا. دائمًا!
يشكّل الحدث unload
مشكلة للمتصفّحات لأنّه يعود إلى ما قبل bfcache، وتعمل العديد من الصفحات على الإنترنت بافتراض (معقول) بأنّ الصفحة لن تستمر في الظهور بعد بدء الحدث unload
. يشكّل ذلك تحديًا لأنّ العديد من هذه الصفحات تم إنشاؤها أيضًا بافتراض أنّه سيتم بدء الحدث unload
في أي وقت ينتقل فيه المستخدِم بعيدًا، وهذا لم يعُد صحيحًا (لم يكن صحيحًا منذ فترة طويلة).
لذا، تواجه المتصفّحات معضلة، إذ عليها الاختيار بين إجراء يمكن أن يُحسِّن تجربة المستخدم، ولكن قد يؤدي أيضًا إلى تعطُّل الصفحة.
على أجهزة الكمبيوتر المكتبي، اختار Chrome وFirefox جعل الصفحات غير مؤهَّلة لاستخدام bfcache في حال إضافة مستمع unload
، وهو إجراء أقل خطورة، ولكنه يُقصِّر أيضًا الكثير من الصفحات. سيحاول متصفّح Safari تخزين بعض الصفحات في ذاكرة التخزين المؤقت باستخدام أداة معالجة الأحداث "unload
"، ولكن للحدّ من الأعطال المحتمَلة، لن يشغّل حدث "unload
" أثناء مغادرة المستخدم، ما يجعل الحدث غير موثوق به إلى حدّ كبير.
على الأجهزة الجوّالة، سيحاول Chrome وSafari تخزين الصفحات في ذاكرة التخزين المؤقت باستخدام أداة معالجة الأحداث unload
لأنّ مخاطر حدوث أعطال في تلك الأجهزة كانت منخفضة لأنّ حدث unload
كان دائمًا غير موثوق به على الأجهزة الجوّالة. يتعامل Firefox مع الصفحات التي تستخدم unload
على أنّها غير مؤهّلة لاستخدام ميزة "التخزين المؤقت للصفحات"، باستثناء نظام التشغيل iOS الذي يتطلّب من جميع المتصفّحات استخدام محرّك عرض WebKit، وبالتالي يتصرّف مثل Safari.
بدلاً من استخدام الحدث unload
، استخدِم الحدث pagehide
. يتم تنشيط الحدث pagehide
في جميع الحالات التي يتم فيها تنشيط الحدث unload
، ويتم تنشيط الحدث أيضًا عند وضع صفحة في bfcache.
في الواقع، يتضمّن Lighthouse تدقيق no-unload-listeners
، والذي سيحذّر المطوّرين إذا كان أيّ رمز JavaScript على صفحاتهم (بما في ذلك الرموز من المكتبات التابعة لجهات خارجية) يضيف مستمع أحداث unload
.
بسبب عدم موثوقية هذا الحدث وتأثيره في أداء bfcache، يسعى Chrome إلى إيقاف حدث unload
نهائيًا.
استخدام سياسة الأذونات لمنع استخدام عناصر معالجة إلغاء التحميل في صفحة
يمكن للمواقع الإلكترونية التي لا تستخدم معالِجات أحداث "unload
" ضمان عدم إضافتها باستخدام سياسة الأذونات.
Permission-Policy: unload=()
ويمنع ذلك أيضًا الجهات الخارجية أو الإضافات من إبطاء أداء الموقع الإلكتروني من خلال إضافة معالِجات إلغاء التحميل وجعل الموقع الإلكتروني غير مؤهَّل لاستخدام ميزة "التخزين المؤقت للصفحات".
إضافة beforeunload
مستمع فقط بشكل مشروط
لن يؤدي حدث beforeunload
إلى جعل صفحاتك غير مؤهَّلة لاستخدام ميزة "التخزين المؤقت للصفحات" في المتصفحات الحديثة، ولكنّه كان يؤدي إلى ذلك في السابق ولا يزال غير موثوق به، لذا تجنَّب استخدامه ما لم يكن ضروريًا للغاية.
ومع ذلك، على عكس حدث unload
، هناك استخدامات مشروعة لـ
beforeunload
. على سبيل المثال، عندما تريد تحذير المستخدم من أنّه لديه
تغييرات لم يتم حفظها وستفقدها إذا غادر الصفحة. في هذه الحالة، ننصح بعدم إضافة مستمعين إلا عندما يكون لدى المستخدِم
تغييرات غير محفوظة، ثم إزالتهم فورًا بعد حفظ التغييرات غير المحفوظة.
window.addEventListener('beforeunload', (event) => {
if (pageHasUnsavedChanges()) {
event.preventDefault();
return event.returnValue = 'Are you sure you want to exit?';
}
});
function beforeUnloadListener(event) {
event.preventDefault();
return event.returnValue = 'Are you sure you want to exit?';
};
// A function that invokes a callback when the page has unsaved changes.
onPageHasUnsavedChanges(() => {
window.addEventListener('beforeunload', beforeUnloadListener);
});
// A function that invokes a callback when the page's unsaved changes are resolved.
onAllChangesSaved(() => {
window.removeEventListener('beforeunload', beforeUnloadListener);
});
تقليل استخدام "Cache-Control: no-store
"
Cache-Control: no-store
هو عنوان HTTP يمكن لخوادم الويب ضبطه على الاستجابات التي توجّه المتصفّح إلى عدم تخزين الاستجابة في أي ذاكرة تخزين مؤقت لبروتوكول HTTP. ويتم استخدامه للموارد التي تحتوي على معلومات حساسة للمستخدمين، مثل الصفحات المحمية بتسجيل الدخول.
على الرغم من أنّ ميزة "التخزين المؤقت للصفحات" ليست ذاكرة تخزين مؤقت لبروتوكول HTTP، إلا أنّ المتصفّحات كانت تختار في السابق عدم تخزين الصفحة في ميزة "التخزين المؤقت للصفحات" عند ضبط Cache-Control: no-store
على مورد الصفحة نفسه (بدلاً من أيّ مورد فرعي)، لذا قد لا تكون أيّ صفحات تستخدم Cache-Control: no-store
مؤهّلة لاستخدام ميزة "التخزين المؤقت للصفحات". وثمة عمل قيد العمل لتغيير هذا السلوك في Chrome بطريقة تحافظ على الخصوصية.
بما أنّ Cache-Control: no-store
يحدّ من أهلية الصفحة لاستخدام ذاكرة التخزين المؤقت للصفحات (bfcache)، يجب ضبطه فقط على الصفحات التي تحتوي على معلومات حسّاسة حيث لا يكون التخزين المؤقت بأي شكل من الأشكال مناسبًا.
بالنسبة إلى الصفحات التي يجب أن تعرض دائمًا محتوى محدّثًا، ولا يحتوي هذا المحتوى على معلومات حسّاسة، استخدِم Cache-Control: no-cache
أو Cache-Control: max-age=0
. تُوجّه هذه التوجيهات المتصفّح إلى إعادة التحقّق من صحة المحتوى قبل عرضه، ولا تؤثّر في أهلية الصفحة لاستخدام ذاكرة التخزين المؤقت bfcache.
يُرجى العلم أنّه عند استعادة صفحة من ذاكرة التخزين المؤقت للصفحات (bfcache)، تتم استعادتها من الذاكرة، وليس من ذاكرة التخزين المؤقت لبروتوكول HTTP. نتيجةً لذلك، لا يتم أخذ توجيهات مثل Cache-Control: no-cache
أو Cache-Control: max-age=0
في الاعتبار، ولا تتم إعادة التحقّق من الصحة قبل عرض المحتوى للمستخدم.
لا تزال هذه التجربة تقدّم على الأرجح تجربة أفضل للمستخدم، لأنّه من غير المرجّح أن يكون المحتوى قديمًا، وذلك لأنّ عمليات استعادة ذاكرة التخزين المؤقت تتم بشكل فوري وبما أنّ الصفحات لا تبقى في ذاكرة التخزين المؤقت هذه لفترة طويلة جدًا. ومع ذلك، إذا كان المحتوى يتغيّر كل دقيقة، يمكنك جلب أي تعديلات باستخدام الحدث pageshow
، كما هو موضّح في القسم التالي.
تعديل البيانات القديمة أو الحسّاسة بعد استعادة bfcache
إذا كان موقعك الإلكتروني يحتفظ بحالة المستخدم، خاصةً أي معلومات حسّاسة للمستخدم، يجب تعديل هذه البيانات أو محوها بعد استعادة صفحة من bfcache.
على سبيل المثال، إذا انتقل أحد المستخدِمين إلى صفحة دفع ثم عدّل سلة التسوّق، قد يؤدي التنقّل للخلف إلى عرض معلومات قديمة إذا تم استعادة صفحة قديمة من bfcache.
من الأمثلة الأخرى الأكثر أهمية على ذلك هو إذا سجّل مستخدم الخروج من موقع إلكتروني على كمبيوتر عام ثم نقر المستخدم التالي على زر الرجوع. وقد يؤدي ذلك إلى الكشف عن بيانات خاصة كان المستخدم يعتقد أنّه تم محوّها عند تسجيل الخروج.
لتجنُّب حدوث مواقف مماثلة، من الأفضل تعديل الصفحة دائمًا بعد حدث pageshow
إذا كان event.persisted
يساوي true
:
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
// Do any checks and updates to the page
}
});
من الأفضل تعديل المحتوى في مكانه، ولكن قد تحتاج إلى فرض إعادة تحميل كاملة لبعض التغييرات. يتحقّق الرمز التالي من توفُّر ملف تعريف ارتباط خاص بالموقع الإلكتروني في حدث pageshow
، ويُعاد تحميله في حال عدم العثور على ملف تعريف الارتباط:
window.addEventListener('pageshow', (event) => {
if (event.persisted && !document.cookie.match(/my-cookie)) {
// Force a reload if the user has logged out.
location.reload();
}
});
تتمتع عملية إعادة التحميل بميزة الاحتفاظ بالسجلّ (لإتاحة عمليات الانتقال للأمام)، ولكن قد تكون عملية إعادة التوجيه أكثر ملاءمةً في بعض الحالات.
استعادة الإعلانات وميزة "التخزين المؤقت للصفحات"
قد يكون من المغري محاولة تجنُّب استخدام ميزة "التخزين المؤقت للصفحات" (bfcache) لعرض مجموعة جديدة من الإعلانات عند كل عملية انتقال إلى الخلف أو إلى الأمام. ومع ذلك، بالإضافة إلى التأثير في الأداء، يشكّل هذا السلوك مسألةً مثيرةً للجدل حول ما إذا كان يؤدي إلى تفاعل أفضل مع الإعلانات. قد يكون المستخدمون قد لاحظوا إعلانًا أرادوا العودة إليه للنقر عليه، ولكنّهم لم يتمكّنوا من ذلك بسبب إعادة التحميل بدلاً من الاستعادة من ذاكرة التخزين المؤقت bfcache. من المهم اختبار هذا السيناريو، ويُفضّل إجراء اختبار أ/ب، قبل وضع أي افتراضات.
بالنسبة إلى المواقع الإلكترونية التي تريد إعادة تحميل الإعلانات عند استعادة bfcache، فإنّ إعادة تحميل الإعلانات فقط في حدث pageshow
عندما يكون event.persisted
هو true
يسمح بحدوث ذلك بدون التأثير في أداء الصفحة. يمكنك الرجوع إلى مزوّد الإعلانات، ولكن إليك مثال واحد على كيفية إجراء ذلك باستخدام علامة الناشر من Google.
تجنُّب استخدام مراجع window.opener
في المتصفحات القديمة، إذا تم فتح صفحة باستخدام window.open()
من رابط يتضمّن target=_blank
، بدون تحديد rel="noopener"
، ستحتوي الصفحة الافتتاحية على إشارة إلى عنصر النافذة للصفحة المفتوحة.
بالإضافة إلى المخاطر الأمنية، لا يمكن وضع صفحة تحتوي على مرجع window.opener
غير صفري في bfcache بأمان، لأنّ ذلك قد يؤدي إلى تعطيل أي صفحات تحاول الوصول إليها.
نتيجةً لذلك، من الأفضل تجنُّب إنشاء مراجع window.opener
. يمكنك إجراء ذلك باستخدام rel="noopener"
كلما أمكن (يُرجى العِلم أنّ هذا الخيار هو الإعداد التلقائي الآن في جميع المتصفّحات الحديثة). إذا كان موقعك الإلكتروني يتطلّب فتح نافذة والتحكّم فيها من خلال window.postMessage()
أو الإشارة مباشرةً إلى عنصر النافذة، لن تكون النافذة المفتوحة أو النافذة المفتوحة مؤهّلة لاستخدام bfcache.
إغلاق الاتصالات المفتوحة قبل أن ينتقل المستخدم
كما ذكرنا سابقًا، عند الاحتفاظ بصفحة في ذاكرة التخزين المؤقت bfcache، يتم إيقاف جميع مهام JavaScript المُجدوَلة مؤقتًا واستئنافها عند إزالة الصفحة من ذاكرة التخزين المؤقت.
إذا كانت مهام JavaScript المُجدوَلة هذه تصل إلى واجهات برمجة تطبيقات DOM فقط، أو واجهات برمجة تطبيقات أخرى معزولة على الصفحة الحالية فقط، لن يتسبب إيقاف هذه المهام مؤقتًا أثناء عدم ظهور الصفحة للمستخدم في حدوث أي مشاكل.
ومع ذلك، إذا كانت هذه المهام مرتبطة بواجهات برمجة تطبيقات يمكن الوصول إليها أيضًا من صفحات أخرى في المصدر نفسه (مثل IndexedDB وWeb Locks وWebSockets)، قد يتسبب ذلك في حدوث مشاكل لأنّ إيقاف هذه المهام مؤقتًا قد يمنع تشغيل الرموز البرمجية في علامات التبويب الأخرى.
نتيجةً لذلك، لن تحاول بعض المتصفّحات وضع صفحة في bfcache في السيناريوهات التالية:
- الصفحات التي تحتوي على اتصال IndexedDB مفتوح
- الصفحات التي تتضمّن طلبات fetch() أو XMLHttpRequest قيد التنفيذ
- الصفحات التي تتضمّن اتصالاً مفتوحًا عبر WebSocket أو WebRTC
إذا كانت صفحتك تستخدم أيًا من واجهات برمجة التطبيقات هذه، ننصحك بشدة بإغلاق عمليات الربط وإزالة أو إلغاء ربط المراقبين أثناء حدث pagehide
أو freeze
. ويسمح ذلك للمتصفّح بتخزين الصفحة مؤقتًا بأمان بدون التأثير في علامات التبويب الأخرى المفتوحة.
بعد ذلك، إذا تم استعادة الصفحة من bfcache، يمكنك إعادة فتح واجهات برمجة التطبيقات هذه أو إعادة ربطها بها أثناء حدث pageshow
أو resume
.
يوضِّح المثال التالي كيفية التأكّد من أنّ الصفحات التي تستخدم IndexedDB مؤهَّلة لاستخدام ميزة bfcache من خلال إغلاق اتصال مفتوح في أداة معالجة الأحداث في pagehide
:
let dbPromise;
function openDB() {
if (!dbPromise) {
dbPromise = new Promise((resolve, reject) => {
const req = indexedDB.open('my-db', 1);
req.onupgradeneeded = () => req.result.createObjectStore('keyval');
req.onerror = () => reject(req.error);
req.onsuccess = () => resolve(req.result);
});
}
return dbPromise;
}
// Close the connection to the database when the user leaves.
window.addEventListener('pagehide', () => {
if (dbPromise) {
dbPromise.then(db => db.close());
dbPromise = null;
}
});
// Open the connection when the page is loaded or restored from bfcache.
window.addEventListener('pageshow', () => openDB());
إجراء اختبار للتأكّد من أنّ صفحاتك قابلة للتخزين المؤقت
يمكن أن تساعدك أدوات مطوّري البرامج في Chrome على اختبار صفحاتك للتأكّد من تحسينها للاستفادة من ميزة bfcache، وتحديد أي مشاكل قد تمنع صفحاتك من أن تكون مؤهّلة.
لاختبار صفحة:
- انتقِل إلى الصفحة في Chrome.
- في أدوات المطوّرين، انتقِل إلى التطبيق -> ذاكرة التخزين المؤقت للرجوع إلى الصفحات السابقة والانتقال إلى الصفحات التالية.
- انقر على الزر تشغيل الاختبار. بعد ذلك، تحاول "أدوات مطوّري البرامج" الانتقال بعيدًا ثم الرجوع مجددًا لتحديد ما إذا كان يمكن استعادة الصفحة من bfcache.
إذا نجح الاختبار، ستظهر في اللوحة رسالة "تمت الاستعادة من ميزة "التخزين المؤقت للصفحات".
وإذا لم تنجح، ستشير اللوحة إلى سبب ذلك. إذا كان السبب يمكنك معالجته بصفتك مطوِّرًا، ستحدّده اللوحة على أنّه قابل للتنفيذ.
في هذا المثال، يؤدي استخدام أداة معالجة أحداث unload
إلى جعل الصفحة غير مؤهَّلة لاستخدام ميزة "التخزين المؤقت للصفحات". يمكنك حلّ هذه المشكلة من خلال التبديل من unload
إلى استخدام pagehide
:
window.addEventListener('pagehide', ...);
window.addEventListener('unload', ...);
أضافت أداة Lighthouse 10.0 أيضًا عملية تدقيق في ذاكرة التخزين المؤقت للبريد الإلكتروني، وهي تُجري اختبارًا مشابهًا. لمزيد من المعلومات، يُرجى الاطّلاع على مستندات تدقيق bfcache.
كيفية تأثير ميزة "التخزين المؤقت للصفحات" في الإحصاءات وقياس الأداء
إذا كنت تستخدم أداة تحليلات لقياس الزيارات إلى موقعك الإلكتروني، قد تلاحظ انخفاضًا في إجمالي عدد مشاهدات الصفحة على الويب التي تم الإبلاغ عنها لأنّ Chrome يتيح استخدام ميزة "التخزين المؤقت للصفحات" لمزيد من المستخدمين.
في الواقع، من المرجّح أنّك تُبلغ عن عدد أقل من مشاهدات الصفحة من المتصفّحات الأخرى التي تُنفّذ bfcache، لأنّ العديد من مكتبات الإحصاءات الشائعة لا تقيس عمليات استعادة bfcache كمشاهدات صفحة جديدة.
لتضمين عمليات استعادة ذاكرة التخزين المؤقت في عدد مشاهدات الصفحة على الويب، يمكنك ضبط أدوات معالجة البيانات للحدث pageshow
والتحقّق من السمة persisted
.
يوضّح المثال التالي كيفية إجراء ذلك باستخدام "إحصاءات Google". من المحتمل أن تستخدم أدوات التحليل الأخرى منطقًا مشابهًا:
// Send a pageview when the page is first loaded.
gtag('event', 'page_view');
window.addEventListener('pageshow', (event) => {
// Send another pageview if the page is restored from bfcache.
if (event.persisted) {
gtag('event', 'page_view');
}
});
قياس نسبة مرات الاستفادة من ذاكرة التخزين المؤقت لملف تعريف الارتباط
يمكنك أيضًا قياس ما إذا تم استخدام ميزة "التخزين المؤقت للصفحات"، للمساعدة في تحديد الصفحات التي لا تستخدم هذه الميزة. ويمكن إجراء ذلك من خلال قياس نوع التنقّل لعمليات تحميل الصفحات:
// Send a navigation_type when the page is first loaded.
gtag('event', 'page_view', {
'navigation_type': performance.getEntriesByType('navigation')[0].type;
});
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
// Send another pageview if the page is restored from bfcache.
gtag('event', 'page_view', {
'navigation_type': 'back_forward_cache';
});
}
});
احتسِب نسبة مرات الاطّلاع على bfcache باستخدام أعداد عمليات التنقّل back_forward
وعمليات التنقّل back_forward_cache
.
من المهم معرفة أنّ هناك عددًا من السيناريوهات، خارج نطاق سيطرة مالكي المواقع الإلكترونية، عندما لا يستخدم التنقّل إلى الخلف/إلى الأمام ذاكرة التخزين المؤقت للرجوع إلى الصفحات السابقة، بما في ذلك:
- عندما يُغلق المستخدم المتصفّح ويشغّله مرة أخرى
- عندما يكرّر المستخدم علامة تبويب
- عندما يغلق المستخدِم علامة تبويب ويعيد فتحها
في بعض هذه الحالات، قد تحتفظ بعض المتصفّحات بنوع التنقّل الأصلي، لذلك قد يعرض نوع التنقّل back_forward
على الرغم من أنّ هذا النوع من التنقّل لا يمثّل انتقالات للخلف أو للأمام.
حتى بدون هذه الاستبعادات، سيتم تجاهل ميزة "التخزين المؤقت للصفحات" بعد فترة للحفاظ على الذاكرة.
ولذلك، من غير المتوقّع أن يتوقّع مالكو المواقع الإلكترونية نسبة نتائج تخزين مؤقت بنسبة 100% في جميع عمليات تنقل back_forward
. ومع ذلك، يمكن أن يكون قياس نسبة هذه الروابط مفيدًا لتحديد الصفحات التي تمنع فيها الصفحة نفسها استخدام ميزة "التخزين المؤقت للصفحات" لنسبة عالية من عمليات الانتقال للخلف وللأمام.
أضاف فريق Chrome واجهة برمجة التطبيقات NotRestoredReasons
API للمساعدة في الكشف عن أسباب عدم استخدام الصفحات لذاكرة التخزين المؤقت bfcache، حتى يتمكّن المطوّرون من تحسين معدّلات الاطّلاع على ذاكرة التخزين المؤقت bfcache. أضاف فريق Chrome أيضًا أنواع التنقّل إلى CrUX، ما يتيح الاطّلاع على عدد عمليات التنقّل في bfcache حتى بدون قياسها بنفسك.
قياس الأداء
يمكن أن تؤثر ميزة bfcache بشكل سلبي أيضًا في مقاييس الأداء التي يتم جمعها في الحقل، وتحديدًا المقاييس التي تقيس أوقات تحميل الصفحات.
بما أنّ عمليات التنقّل في bfcache تُعيد صفحة حالية بدلاً من بدء تحميل صفحة جديدة، سينخفض إجمالي عدد عمليات تحميل الصفحات التي يتم جمعها عند تفعيل bfcache. من المهمّ الإشارة إلى أنّ عمليات تحميل الصفحات التي يتم استبدالها بعملية استعادة bfcache من المرجّح أن تكون من أسرع عمليات تحميل الصفحات في مجموعة بياناتك. ويرجع ذلك إلى أنّ عمليات التنقّل للخلف وللأمام هي، بحكم التعريف، زيارات متكرّرة، ويكون تحميل الصفحات المتكرّر أسرع بشكل عام من عمليات تحميل الصفحات من الزوّار لأول مرة (بسبب تخزين HTTP المؤقت، كما ذكرنا سابقًا).
والنتيجة هي انخفاض عدد عمليات تحميل الصفحات السريعة في مجموعة البيانات، ما سيؤدي على الأرجح إلى انحراف التوزيع بشكل أبطأ، على الرغم من أنّ الأداء الذي يشهده المستخدم قد تحسّن على الأرجح.
هناك عدة طرق للتعامل مع هذه المشكلة. أحدهما لإضافة تعليق توضيحي على جميع مقاييس تحميل الصفحات باستخدام نوع التنقّل المناسب لها: navigate
أو reload
أو back_forward
أو prerender
. يتيح لك ذلك مواصلة مراقبة أدائك ضمن أنواع التنقّل هذه، حتى إذا كان التوزيع العام منحازًا بشكل سلبي. ننصح باستخدام هذا النهج لمقاييس تحميل الصفحة غير المستندة إلى المستخدِم، مثل وقت وصول أول بايت (TTFB).
بالنسبة إلى المقاييس التي تركّز على المستخدِم، مثل مؤشرات أداء الويب الأساسية، من الأفضل الإبلاغ عن قيمة تمثّل بشكل أدق ما يواجهه المستخدِم.
التأثير في "مؤشرات أداء الويب الأساسية"
تقيس مؤشرات أداء الويب الأساسية تجربة المستخدم في صفحة الويب على مستوى مجموعة متنوعة من السمات (سرعة التحميل والتفاعل والثبات البصري)، وبما أنّ المستخدمين يلاحظون استعادة ذاكرة التخزين المؤقت للبريد الإلكتروني (bfcache) أثناء عمليات التنقّل الأسرع من عمليات تحميل الصفحة بالكامل، من المهم أن تعكس مقاييس "مؤشرات أداء الويب الأساسية" ذلك. بعد كل شيء، لا يهتم المستخدم بما إذا كان قد تم تفعيل ميزة bfcache أم لا، بل يهتم فقط بأن يكون التنقّل سريعًا.
إنّ الأدوات التي تجمع مقاييس "مؤشرات أداء الويب الأساسية" وتعدّ تقارير عنها، مثل تقرير تجربة المستخدم على Chrome، تتعامل مع عمليات استعادة ميزة "التخزين المؤقت للصفحات" باعتبارها زيارات منفصلة للصفحات في مجموعة البيانات الخاصة بها. على الرغم من عدم توفّر واجهات برمجة تطبيقات مخصّصة لأداء الويب لقياس هذه المقاييس بعد استعادة bfcache، يمكنك تقريب قيمها باستخدام واجهات برمجة تطبيقات الويب الحالية:
- بالنسبة إلى سرعة عرض أكبر محتوى مرئي (LCP)، استخدِم الفرق بين الطابع الزمني لحدث
pageshow
والطابع الزمني للإطار المرسوم التالي، لأنّه سيتمّ رسم جميع العناصر في الإطار في الوقت نفسه. في حال استعادة bfcache، يكون LCP وFCP متماثلين. - بالنسبة إلى مدى استجابة الصفحة لتفاعلات المستخدم (INP)، يُرجى مواصلة استخدام أداة "مراقبة الأداء" الحالية، ولكن عليك إعادة ضبط قيمة INP الحالية على 0.
- بالنسبة إلى متغيّرات التصميم التراكمية (CLS)، يُرجى مواصلة استخدام أداة "مراقبة الأداء" الحالية، ولكن عليك إعادة ضبط قيمة CLS الحالية على 0.
لمزيد من التفاصيل حول كيفية تأثير ميزة "التخزين المؤقت للصفحات" في كل مقياس، يمكنك الاطّلاع على صفحات أدلة المقاييس الفردية في "مؤشرات أداء الويب الأساسية". للاطّلاع على مثال محدّد عن كيفية تنفيذ إصدارات ميزة "التخزين المؤقت للصفحات" من هذه المقاييس، يمكنك الرجوع إلى قسم PR إضافتها إلى مكتبة JavaScript لمؤشرات أداء الويب.
توفّر مكتبة JavaScript الخاصة بخدمة web-vitals إمكانية استعادة bfcache في المقاييس التي تسجّلها.
موارد إضافية
- ذاكرة التخزين المؤقت في Firefox (bfcache في Firefox)
- Page cache (bfcache في Safari)
- ذاكرة التخزين المؤقت للصفحات السابقة/التالية: السلوك المعروض على الويب (الاختلافات في ذاكرة التخزين المؤقت للصفحات السابقة/التالية في المتصفّحات المختلفة)
- أداة اختبار ميزة "التخزين المؤقت للصفحات" (اختبار تأثير واجهات برمجة التطبيقات والأحداث المختلفة في ميزة "التخزين المؤقت للصفحات" في المتصفّحات)
- ميزة تقدّم تحسينًا كبيرًا في الأداء: ميزة "التخزين المؤقت للصفحات" في المتصفّح (دراسة حالة من Smashing Magazine تعرض تحسينات كبيرة في "مؤشرات الأداء الرئيسية للويب" من خلال تفعيل ميزة "التخزين المؤقت للصفحات")