ميزة "التخزين المؤقت للصفحات" (أو 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؟
الإجابة هي أنّ المتصفّحات تُوقِف مؤقتًا أيّ أدوات ضبط وقت أو وعد غير محسَّن للصفحات في ذاكرة التخزين المؤقت bfcache، بما في ذلك جميع المهام التي لا تزال قيد المراجعة تقريبًا في قوائم انتظار مهام JavaScript، وتستأنف معالجة المهام في حال استعادة الصفحة من ذاكرة التخزين المؤقت bfcache.
في بعض الحالات، مثل حالات وقت الاستراحة والوعد، تكون هذه المخاطر منخفضة إلى حدٍ ما، ولكن في حالات أخرى، يمكن أن تؤدي إلى سلوك مربك أو غير متوقّع. على سبيل المثال، إذا أوقف المتصفح مؤقتًا مهمة مطلوبة كجزء من معاملة IndexedDB، يمكن أن يؤثر ذلك في علامات التبويب المفتوحة الأخرى في المصدر نفسه، لأنّه يمكن الوصول إلى قواعد بيانات IndexedDB نفسها من خلال علامات تبويب متعددة في الوقت نفسه. ونتيجةً لذلك، لن تحاول المتصفّحات بشكل عام تخزين صفحات مؤقتًا في منتصف معاملة IndexedDB أو أثناء استخدام واجهات برمجة تطبيقات قد تؤثّر في صفحات أخرى.
لمزيد من التفاصيل حول كيفية تأثير استخدامات واجهات برمجة التطبيقات المختلفة في أهلية صفحة لاستخدام ميزة "التخزين المؤقت للصفحات"، اطّلِع على مقالة تحسين صفحاتك لاستخدام ميزة "التخزين المؤقت للصفحات".
ميزة "التخزين المؤقت للصفحات" وإطارات iframe
إذا كانت الصفحة تحتوي على أطر iframe مضمّنة، تكون أطر iframe نفسها غير مؤهَّلة لاستخدام ميزة "التخزين المؤقت للصفحات". على سبيل المثال، إذا انتقلت إلى صفحة أخرى ضمن إطار iframe، ثم عدت إلى الوراء، سينتقل المتصفّح إلى "الخلف" ضمن إطار iframe بدلاً من الإطار الرئيسي، ولكن لن يستخدم التنقّل للخلف ضمن إطار iframe ذاكرة التخزين المؤقت bfcache.
يمكن أيضًا حظر الإطار الرئيسي من استخدام ميزة "التخزين المؤقت للصفحات" إذا كان إطار iframe مضمّنًا يستخدم واجهات برمجة تطبيقات تحظر ذلك. يمكن استخدام سياسة الأذونات التي تم ضبطها على الإطار الرئيسي أو استخدام سمات sandbox
لتجنُّب ذلك.
ميزة "التخزين المؤقت للصفحات" والتطبيقات من صفحة واحدة
وبما أنّ ذاكرة التخزين المؤقت bfcache تعمل مع عمليات التنقّل التي يديرها المتصفّح، لا تعمل مع "عمليات التنقّل الناعمة" ضمن تطبيق صفحة واحدة. ومع ذلك، لا يزال بإمكان 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
التأكّد من عدم إضافتها باستخدام سياسة الأذونات.
Permissions-Policy: unload=()
ويمنع هذا الإجراء أيضًا الجهات الخارجية أو الإضافات من إبطاء الموقع الإلكتروني عن طريق إضافة عناصر تحكّم في التفريغ وجعل الموقع الإلكتروني غير مؤهَّل لاستخدام ذاكرة التخزين المؤقت bfcache.
إضافة beforeunload
مستمع فقط بشكل مشروط
لن يؤدي حدث beforeunload
إلى جعل صفحاتك غير مؤهَّلة لاستخدام ميزة "التخزين المؤقت للصفحات" في المتصفحات الحديثة، ولكنّه كان يفعل ذلك في السابق ولا يزال غير موثوق به، لذا تجنَّب استخدامه ما لم يكن ضروريًا للغاية.
على عكس حدث unload
، هناك استخدامات مشروعة لحالة
beforeunload
. على سبيل المثال، عندما تريد تحذير المستخدم من أنّه لديه
تغييرات لم يتم حفظها وستفقدها إذا غادر الصفحة. في هذه الحالة، ننصح بعدم إضافة مستمعين إلا عندما يكون لدى المستخدِم
تغييرات غير محفوظة، ثم إزالتهم فورًا بعد حفظ التغييرات غير المحفوظة.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
في الاعتبار، ولا تتم إعادة التحقّق من الصحة قبل عرض المحتوى للمستخدم.
ومع ذلك، من المرجّح أنّ هذه الطريقة توفّر تجربة أفضل للمستخدم، لأنّ استعادة bfcache تكون فورية، ومن غير المرجّح أن يكون المحتوى قديمًا لأنّ الصفحات لا تبقى في bfcache لفترة طويلة جدًا. ومع ذلك، إذا كان المحتوى يتغيّر كل دقيقة، يمكنك جلب أي تعديلات باستخدام الحدث 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', ...);
أضاف الإصدار 10.0 من Lighthouse أيضًا تدقيقًا في ذاكرة التخزين المؤقت للبريد الإلكتروني، الذي يُجري اختبارًا مشابهًا. لمزيد من المعلومات، يُرجى الاطّلاع على مستندات تدقيق bfcache.
تأثير ذاكرة التخزين المؤقت bfcache في الإحصاءات وقياس الأداء
إذا كنت تستخدم أداة إحصاءات لقياس الزيارات إلى موقعك الإلكتروني، قد تلاحظ انخفاضًا في إجمالي عدد مرّات مشاهدة الصفحة التي يتم الإبلاغ عنها عندما يفعّل Chrome ذاكرة التخزين المؤقت bfcache لعدد أكبر من المستخدمين.
في الواقع، من المرجّح أنّك تُبلغ عن عدد أقل من مشاهدات الصفحة من المتصفّحات الأخرى التي تُنفّذ bfcache، لأنّ العديد من مكتبات الإحصاءات الشائعة لا تقيس عمليات استعادة 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
.
من المهم معرفة أنّ هناك عددًا من السيناريوهات، خارج نطاق سيطرة مالكي المواقع الإلكترونية، عندما لا تستخدم ميزة التنقّل "للخلف/للأمام" ذاكرة التخزين المؤقت bfcache، بما في ذلك:
- عندما يُغلق المستخدم المتصفّح ويشغّله مرة أخرى
- عندما يكرّر المستخدم علامة تبويب
- عندما يغلق المستخدِم علامة تبويب ويعيد فتحها
في بعض هذه الحالات، قد تحافظ بعض المتصفّحات على نوع التنقّل الأصلي، وبالتالي قد تعرض نوعًا من back_forward
على الرغم من أنّ هذه ليست عمليات تنقّل للخلف/للأمام.
حتى في حال عدم تطبيق هذه الاستثناءات، سيتم تجاهل bfcache بعد فترة للحفاظ على الذاكرة.
لذلك، لا يتوقع مالكو المواقع الإلكترونية نسبة طلبات بحث ناجحة في ذاكرة التخزين المؤقت لصفحات الويب بنسبة% 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 على أنّها زيارات منفصلة للصفحات في مجموعة بياناتها. على الرغم من عدم توفّر واجهات برمجة تطبيقات مخصّصة لأداء الويب لقياس هذه المقاييس بعد استعادة bfcache، يمكنك تقريب قيمها باستخدام واجهات برمجة تطبيقات الويب الحالية:
- بالنسبة إلى سرعة عرض أكبر محتوى مرئي (LCP)، استخدِم الفرق بين الطابع الزمني لحدث
pageshow
والطابع الزمني للإطار المرسوم التالي، لأنّه سيتمّ رسم جميع العناصر في الإطار في الوقت نفسه. في حال استعادة bfcache، يكون LCP وFCP متماثلين. - بالنسبة إلى مدى استجابة الصفحة لتفاعلات المستخدم (INP)، يُرجى مواصلة استخدام أداة "مراقبة الأداء" الحالية، ولكن عليك إعادة ضبط قيمة INP الحالية على 0.
- بالنسبة إلى متغيّرات التصميم التراكمية (CLS)، يُرجى مواصلة استخدام أداة "مراقبة الأداء" الحالية، ولكن عليك إعادة ضبط قيمة CLS الحالية على 0.
لمزيد من التفاصيل عن كيفية تأثير bfcache في كل مقياس، اطّلِع على صفحات أدلة المقاييس الفردية الخاصة بـ "مؤشرات أداء الويب الأساسية". للحصول على مثال محدّد على كيفية تنفيذ إصدارات bfcache من هذه المقاييس، يُرجى الرجوع إلى PR adding them to the web-vitals JS library.
توفّر مكتبة JavaScript web-vitals إمكانية استعادة bfcache في المقاييس التي تسجّلها.
موارد إضافية
- ذاكرة التخزين المؤقت في Firefox (bfcache في Firefox)
- ذاكرة التخزين المؤقت للصفحات (bfcache في Safari)
- ذاكرة التخزين المؤقت للصفحات السابقة/التالية: السلوك المعروض على الويب (الاختلافات في ذاكرة التخزين المؤقت للصفحات السابقة/التالية في المتصفّحات المختلفة)
- أداة اختبار ميزة "التخزين المؤقت للصفحات" (اختبار تأثير واجهات برمجة التطبيقات والأحداث المختلفة في ميزة "التخزين المؤقت للصفحات" في المتصفّحات)
- ميزة تقدّم تحسينًا كبيرًا في الأداء: ميزة "التخزين المؤقت للصفحات" في المتصفّح (دراسة حالة من Smashing Magazine توضّح تحسينات كبيرة في "مؤشرات الأداء الرئيسية للويب" من خلال تفعيل ميزة "التخزين المؤقت للصفحات")