ميزة "التخزين المؤقت للصفحات"

إنّ ميزة "التخزين المؤقت للصفحات" (أو bfcache) هي تحسين في المتصفّح تتيح إمكانية التنقّل الفوري للرجوع إليها أو إعادة توجيهها. يحسن ذلك بشكل كبير تجربة التصفح، خاصة للمستخدمين الذين لديهم شبكات أو أجهزة أبطأ.

بما أنّ المطوّرين على الويب، من الضروري فهم كيفية تحسين صفحاتك لاستخدام ميزة "التخزين المؤقت للصفحات"، ليتمكّن المستخدمون من الاستفادة من مزاياها.

توافُق المتصفح

كان ميزة bfcache متاحة في كلّ من Firefox وSafari لسنوات عديدة على أجهزة الكمبيوتر المكتبي والأجهزة الجوّالة.

بدءًا من الإصدار 86، فعَّل Chrome ميزة "التخزين المؤقت للصفحات" للتنقّل على مواقع إلكترونية متعددة على نظام التشغيل Android لدى نسبة صغيرة من المستخدمين. وفي الإصدارات اللاحقة، سيتم طرح المزيد من الميزات تدريجيًا. بدءًا من الإصدار 96، تم تفعيل ميزة "التخزين المؤقت للصفحات" لجميع مستخدمي Chrome على أجهزة الكمبيوتر المكتبي والأجهزة الجوّالة.

أساسيات Bfcache

bfcache هي ذاكرة تخزين مؤقت داخل الذاكرة تخزّن لقطة كاملة لإحدى الصفحات (بما في ذلك كومة JavaScript) أثناء انتقال المستخدم بعيدًا. مع وجود الصفحة بأكملها في الذاكرة، يمكن للمتصفح استعادتها بسرعة إذا قرر المستخدم العودة إليها.

كم مرة زرت أحد المواقع الإلكترونية ونقرت على رابط للانتقال إلى صفحة أخرى، لتدرك أنه ليس ما تريده، وتنقر على زر الرجوع؟ في هذه اللحظة، يمكن أن تُحدث ميزة bfcache فارقًا كبيرًا في سرعة تحميل الصفحات السابقة:

بدون تفعيل ميزة "التخزين المؤقت للصفحات" يتم بدء طلب جديد لتحميل الصفحة السابقة، واستنادًا إلى مدى تحسين تلك الصفحة للزيارات المتكررة، قد يحتاج المتصفح إلى إعادة تنزيل بعض (أو كل) الموارد التي تم تنزيلها للتو وإعادة تحليلها وإعادة تنفيذها.
مع تفعيل ميزة "التخزين المؤقت للصفحات" يعد تحميل الصفحة السابقة فوريًا بشكل أساسي، لأنّه يمكن استعادة الصفحة بأكملها من الذاكرة، بدون الحاجة إلى الانتقال إلى الشبكة.

شاهِد هذا الفيديو لاستخدام ميزة "التخزين المؤقت للصفحات" بشكل عملي لفهم سرعته في عمليات التنقّل:

يؤدي استخدام ميزة "التخزين المؤقت للصفحات" إلى تحميل الصفحات بسرعة أكبر أثناء التنقّل للأمام والخلف.

في الفيديو، يكون المثال الذي يتضمّن ميزة bfcache أسرع قليلاً من المثال الذي لا يتضمّنه.

لا يساعد bfcache في تسريع التنقل فحسب، بل يقلل أيضًا من استخدام البيانات، حيث لا حاجة إلى تنزيل الموارد مرة أخرى.

توضّح بيانات استخدام Chrome أنّ عملية انتقال واحدة من كل 10 عمليات على الكمبيوتر المكتبي وأخرى من كل 5 عمليات على الأجهزة الجوّالة تتم للخلف أو للأمام. وبتفعيل ميزة "التخزين المؤقت للصفحات"، يمكن للمتصفحات التخلص من عملية نقل البيانات والوقت المستغرق في تحميل المليارات من صفحات الويب كل يوم.

آلية عمل ميزة "ذاكرة التخزين المؤقت"

تختلف "ذاكرة التخزين المؤقت" التي تستخدمها ميزة "التخزين المؤقت للصفحات" عن ذاكرة التخزين المؤقت لبروتوكول HTTP التي تؤدي دورها الخاص في تسريع عمليات الانتقال المتكرّرة. فميزة "bfcache" هي لقطة للصفحة بالكامل في الذاكرة، بما في ذلك كومة JavaScript، في حين تحتوي ذاكرة التخزين المؤقت لـ HTTP على استجابات الطلبات التي تم تقديمها مسبقًا فقط. نظرًا لأنه من النادر جدًا أن يتم تنفيذ جميع الطلبات المطلوبة لتحميل صفحة من ذاكرة التخزين المؤقت لبروتوكول HTTP، تكون الزيارات المتكررة باستخدام عمليات استعادة ميزة "التخزين المؤقت للصفحات" دائمًا أسرع من عمليات التنقل باستخدام ميزة "التخزين المؤقت للصفحات" الأفضل أداءً.

ومع ذلك، فإن إنشاء لقطة لصفحة في الذاكرة يتضمن بعض التعقيد من حيث أفضل طريقة للحفاظ على التعليمة البرمجية قيد التقدم. على سبيل المثال، كيف يتم التعامل مع طلبات setTimeout() عند الوصول إلى المهلة المحدَّدة أثناء تخزين الصفحة مؤقتًا في ميزة "التخزين المؤقت للصفحات"؟

والإجابة عن هذا السؤال هي أنّ المتصفّحات توقِف مؤقتًا أي موقّتات معلّقة أو وعود لم يتم حلها للصفحات المدرَجة في ميزة "التخزين المؤقت للصفحات"، بما في ذلك جميع المهام المعلَّقة تقريبًا في قوائم الانتظار الخاصة بمهام JavaScript، وكذلك تستأنف مهام المعالجة في حال استعادة الصفحة من ذاكرة التخزين المؤقت لميزة "التخزين المؤقت للصفحات".

وفي بعض الحالات، مثل حالات المهلات والوعود، يكون ذلك خطرًا منخفضًا نوعًا ما، ولكن في حالات أخرى قد يؤدي إلى سلوك محير أو غير متوقّع. على سبيل المثال، إذا أوقف المتصفح مؤقتًا مهمة مطلوبة كجزء من معاملة في قاعدة البيانات المفهرسة، من الممكن أن يؤثر ذلك في علامات التبويب المفتوحة الأخرى في المصدر نفسه، لأنه يمكن الوصول إلى قواعد بيانات IndexedDB نفسها من خلال علامات تبويب متعددة في الوقت نفسه. ونتيجةً لذلك، لن تحاول المتصفّحات بشكل عام تخزين الصفحات مؤقتًا في منتصف عملية IndexedDB أو أثناء استخدام واجهات برمجة التطبيقات التي قد تؤثر على صفحات أخرى.

لمعرفة المزيد من التفاصيل عن كيفية تأثير الاستخدام المتعدد لواجهة برمجة التطبيقات في أهلية ميزة "التخزين المؤقت للصفحات" لإحدى الصفحات، يُرجى الاطّلاع على المقالة تحسين صفحاتك لاستخدام ميزة "التخزين المؤقت للصفحات".

التخزين المؤقت وإطارات iframe

إذا كانت إحدى الصفحات تحتوي على إطارات iframe مضمَّنة، لن تكون إطارات iframe نفسها مؤهَّلة لاستخدام ميزة "التخزين المؤقت للصفحات". على سبيل المثال، إذا انتقلت إلى صفحة أخرى داخل إطار iframe، ثم رجعت، سينتقل المتصفّح إلى "رجوع" داخل إطار iframe بدلاً من الإطار الرئيسي، ولكن لن يستخدم شريط التنقّل للخلف في إطار iframe ميزة "التخزين المؤقت للصفحات".

يمكن أيضًا منع الإطار الرئيسي من استخدام ذاكرة التخزين المؤقت إذا كان إطار iframe مضمَّن يستخدم واجهات برمجة تطبيقات تحظر ذلك. لتجنّب ذلك، يمكن استخدام سياسة الأذونات التي تم ضبطها في الإطار الرئيسي أو استخدام سمات sandbox.

ميزة "التخزين المؤقت للصفحات" وتطبيقات الصفحة الواحدة (SPA)

بما أنّ ميزة "التخزين المؤقت للصفحات" تعمل مع عمليات التنقّل التي يديرها المتصفّح، لا تعمل مع "عمليات التنقّل لينة" داخل تطبيق من صفحة واحدة (SPA). ومع ذلك، يمكن أن تساعدك ميزة "التخزين المؤقت للصفحات" عند الرجوع إلى منتجع صحي بدلاً من إعادة إعداد التطبيق بشكل كامل من البداية.

واجهات برمجة التطبيقات لمراقبة ذاكرة التخزين المؤقت للصفحات

على الرغم من أنّ ميزة "التخزين المؤقت للصفحات" هي عبارة عن تحسين يتم إجراؤه في المتصفّحات تلقائيًا، لا يزال من المهم للمطوّرين معرفة وقت حدوثه ليتمكّنوا من تحسين صفحاتهم كي يتم تحسينه وتعديل أي مقاييس أو قياس للأداء وفقًا لذلك.

إنّ الحدثَين الأساسيَين المستخدَمَين لمراقبة التخزين المؤقت للصفحات هي حدثا نقل الصفحة pageshow وpagehide، واللذَين يتوافقان مع معظم المتصفّحات.

يتم أيضًا إرسال حدثَي دورة حياة الصفحة الأحدثَين، freeze وresume، عند الدخول إلى الصفحات في ذاكرة التخزين المؤقت أو تركها مؤقتًا، كما في بعض الحالات الأخرى، على سبيل المثال، عندما يتم تجميد علامة تبويب في الخلفية لتقليل استخدام وحدة المعالجة المركزية (CPU). ولا تتوفّر هذه الأحداث إلا في المتصفّحات المستندة إلى Chromium.

رصد عملية استعادة صفحة من ميزة "التخزين المؤقت للصفحات"

يتم تنشيط حدث pageshow مباشرةً بعد الحدث load عندما تبدأ عملية تحميل الصفحة وفي أي وقت تتم فيه استعادتها من ميزة "التخزين المؤقت للصفحات". يحتوي الحدث pageshow على السمة persisted، وهي true في حال استعادة الصفحة من ميزة "التخزين المؤقت للصفحات" وfalse في الحالات الأخرى. يمكنك استخدام السمة persisted للتمييز بين عمليات تحميل الصفحات العادية وعمليات استعادة ميزة "التخزين المؤقت للصفحات". مثلاً:

window.addEventListener('pageshow', (event) => {
  if (event.persisted) {
    console.log('This page was restored from the bfcache.');
  } else {
    console.log('This page was loaded normally.');
  }
});

في المتصفِّحات التي تتيح استخدام واجهة برمجة تطبيقات (API) دورة حياة الصفحة، يتم تنشيط الحدث resume عند استعادة الصفحات من ذاكرة التخزين المؤقت لميزة "التخزين المؤقت للصفحات" (قبل حدث pageshow مباشرةً) وعندما يعيد المستخدم زيارة علامة تبويب في الخلفية مجمّدة. إذا كنت تريد تعديل حالة صفحة بعد تجميدها (بما في ذلك الصفحات المدرَجة في ميزة "التخزين المؤقت للصفحات")، يمكنك استخدام الحدث resume، ولكن إذا كنت تريد قياس معدّل نتائج ميزة "التخزين المؤقت للصفحات" على موقعك الإلكتروني، عليك استخدام الحدث pageshow. وفي بعض الحالات، قد تحتاج إلى استخدام كليهما.

للحصول على تفاصيل عن أفضل ممارسات قياس ميزة "التخزين المؤقت للصفحات"، يُرجى الاطّلاع على كيفية تأثير استخدام ميزة "التخزين المؤقت للصفحات" في قياس الإحصاءات والأداء.

رصد عملية إدخال ميزة "التخزين المؤقت للصفحات" في إحدى الصفحات

يتم تنشيط الحدث pagehide إما عند إلغاء تحميل صفحة أو عندما يحاول المتصفّح وضعها في ذاكرة التخزين المؤقت لميزة "التخزين المؤقت للصفحات".

يتضمّن حدث "pagehide" أيضًا السمة persisted. إذا كان الملف false، يمكنك أن تتأكد من أنّ الصفحة ليست على وشك الدخول إلى ميزة "التخزين المؤقت للصفحات". مع ذلك، إذا كانت قيمة السمة persisted هي true، لا يضمن ذلك أنّه سيتم تخزين الصفحة مؤقتًا. يعني ذلك أنّ المتصفّح intends إلى تخزين الصفحة في ذاكرة التخزين المؤقت، ولكن قد تكون هناك عوامل أخرى تعيق عمل التخزين المؤقت.

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، ولكن هذا يعني أن المتصفّح intends فقط إلى تخزين الصفحة في ذاكرة التخزين المؤقت. قد يظل عليه تجاهله لعدد من الأسباب التي سيتم توضيحها لاحقًا.

تحسين صفحاتك لاستخدام ميزة "التخزين المؤقت للصفحات"

لا يتم تخزين جميع الصفحات في ميزة "التخزين المؤقت للصفحات"، وحتى عند تخزين الصفحة هناك، لن تظل هناك إلى أجل غير مسمى. من الضروري أن يفهم المطوّرون العوامل التي تجعل الصفحات مؤهَّلة (وغير مؤهَّلة) لاستخدام ميزة "التخزين المؤقت للصفحات" من أجل زيادة معدّلات نتائج ذاكرة التخزين المؤقت إلى أقصى حد.

توضّح الأقسام التالية أفضل الممارسات التي تسهّل على المتصفّح تخزين صفحاتك في ذاكرة التخزين المؤقت قدر الإمكان.

عدم استخدام حدث "unload" مطلقًا

إنّ أهم طريقة لتحسين ميزة "التخزين المؤقت للصفحات" في جميع المتصفّحات هي عدم استخدام حدث unload مطلقًا. أبدًا!

يمثّل الحدث unload مشكلة في المتصفّحات لأنّه يسبق ميزة "التخزين المؤقت للصفحات" وأنّ العديد من الصفحات على الإنترنت تعمل بافتراض (معقول) أنّ الصفحة لن تبقى متوفرة بعد تنشيط حدث unload. ويمثّل ذلك تحديًا لأنّ العديد من هذه الصفحات تم أيضًا إنشاؤها بافتراض أنّه سيتم تنشيط حدث unload في أي وقت يغادر فيه المستخدم، وهذا الأمر لم يعُد صحيحًا (ولم يكن صحيحًا منذ فترة طويلة).

لذا، تواجه المتصفحات معضلة، وعليها الاختيار من بين خيار يمكنه تحسين تجربة المستخدم، ولكنه قد يخاطر أيضًا بكسر الصفحة.

على أجهزة الكمبيوتر المكتبي، اختار كل من Chrome وFirefox جعل الصفحات غير مؤهَّلة لاستخدام ميزة "التخزين المؤقت للصفحات" في حال إضافة أداة معالجة unload، وهو أمر أقل خطورة ولكنه يستبعد أيضًا الكثير من الصفحات. سيحاول Safari تخزين بعض الصفحات في ذاكرة التخزين المؤقت باستخدام أداة معالجة حدث unload، ولكن للحدّ من الانقطاع المحتمل، لن يشغّل حدث unload أثناء مغادرة المستخدم، ما يجعل الحدث غير موثوق به على الإطلاق.

على الأجهزة الجوّالة، سيحاول Chrome وSafari تخزين الصفحات من خلال أداة معالجة الحدث unload في ذاكرة التخزين المؤقت لأنّ حدث unload كان دائمًا غير موثوق به على الأجهزة الجوّالة. يتعامل متصفّح Firefox مع الصفحات التي تستخدم unload على أنّها غير مؤهَّلة لاستخدام ميزة "التخزين المؤقت للصفحات" باستثناء نظام التشغيل iOS الذي يتطلّب من جميع المتصفحات استخدام محرك عرض WebKit، وبالتالي فإنّه يعمل مثل Safari.

وبدلاً من استخدام حدث "unload"، استخدِم حدث pagehide. يتم تنشيط حدث pagehide في جميع الحالات التي يتم فيها تنشيط الحدث unload، ويتم أيضًا عند إدراج صفحة في ذاكرة التخزين المؤقت للصفحات.

في الواقع، تتضمن Lighthouse عملية تدقيق no-unload-listeners، ستحذّر المطوّرين في حال إضافة أي أداة JavaScript على صفحاتهم (بما في ذلك النص البرمجي من المكتبات التابعة لجهات خارجية) إلى أداة معالجة حدث unload.

بسبب عدم موثوقية هذا الحدث وتأثيره في ميزة "التخزين المؤقت للصفحات"، يسعى Chrome إلى إيقاف حدث "unload" نهائيًا.

يمكنك استخدام "سياسة الأذونات" لمنع استخدام معالِجات إلغاء التحميل على إحدى الصفحات.

يمكن للمواقع الإلكترونية التي لا تستخدم معالِجات أحداث "unload" ضمان عدم إضافتها باستخدام سياسة الأذونات من الإصدار 115 من Chrome.

Permission-Policy: unload()

ويؤدي ذلك أيضًا إلى منع الجهات الخارجية أو الإضافات من إبطاء الموقع الإلكتروني من خلال إضافة معالِجات إلغاء التحميل وجعل الموقع الإلكتروني غير مؤهَّل لاستخدام ميزة "التخزين المؤقت للصفحات".

إضافة أدوات معالجة beforeunload فقط بشكل مشروط

لن يؤدّي الحدث beforeunload إلى جعل صفحاتك غير مؤهَّلة لاستخدام ميزة "التخزين المؤقت للصفحات" في ميزة "التخزين المؤقت للصفحات" في المتصفّحات الحديثة، ولكنّه حدث في السابق ولا يزال غير موثوق، لذا تجنَّب استخدامه إلا عند الضرورة القصوى.

وعلى عكس حدث unload، هناك استخدامات مشروعة لـ beforeunload. على سبيل المثال، عندما تريد تحذير المستخدم بأنّ لديه تغييرات غير محفوظة، سيفقدها في حال مغادرة الصفحة. في هذه الحالة، ننصحك بإضافة مستمعين beforeunload فقط عندما يكون لدى المستخدم تغييرات غير محفوظة، ثم إزالتها على الفور بعد حفظ التغييرات غير المحفوظة.

الإجراءات غير المُوصى بها
window.addEventListener('beforeunload', (event) => {
  if (pageHasUnsavedChanges()) {
    event.preventDefault();
    return event.returnValue = 'Are you sure you want to exit?';
  }
});
يُضيف هذا الرمز أداة معالجة أحداث "beforeunload" بدون أي شروط.
الإجراءات الموصى بها
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);
});
يُضيف هذا الرمز البرمجي مستمع beforeunload فقط عند الحاجة (ويزيله عند عدم الحاجة إليه).

الحدّ من استخدام "Cache-Control: no-store"

Cache-Control: no-store هو عنوان لخوادم الويب يمكن أن يضبط عنوان HTTP على الاستجابات التي توجّه المتصفّح إلى عدم تخزين الاستجابة في أي ذاكرة تخزين مؤقت خاصة ببروتوكول HTTP. إنّها تُستخدم للموارد التي تحتوي على معلومات حساسة للمستخدم، مثل الصفحات المحمية بمعلومات تسجيل دخول.

على الرغم من أنّ ميزة bfcache ليست ذاكرة تخزين مؤقت لبروتوكول HTTP، في السابق، عند ضبط Cache-Control: no-store على مورد الصفحة نفسه (على عكس أي مورد فرعي)، اختارت المتصفّحات عدم تخزين الصفحة في ميزة "التخزين المؤقت للصفحات". جارٍ العمل حاليًا على تغيير هذا السلوك في Chrome بطريقة تحافظ على الخصوصية، إلا أنّ أي صفحات تستخدم Cache-Control: no-store لن تكون مؤهَّلة لاستخدام ميزة "التخزين المؤقت للصفحات".

وبما أنّ Cache-Control: no-store يحدّ من أهلية الصفحة لاستخدام ميزة "التخزين المؤقت للصفحات"، يجب ضبطها فقط على الصفحات التي تحتوي على معلومات حساسة حيث يكون التخزين المؤقت من أي نوع غير ملائم على الإطلاق.

استخدِم Cache-Control: no-cache أو Cache-Control: max-age=0 بالنسبة إلى الصفحات التي تحتاج إلى عرض محتوى حديث دائمًا ولا يتضمّن هذا المحتوى أي معلومات حساسة. وتوجِّه هذه التوجيهات المتصفّح لإعادة التحقّق من المحتوى قبل عرضه، ولا تؤثر في أهلية استخدام ميزة "التخزين المؤقت للصفحات" للصفحة.

يُرجى العِلم أنّه عند استعادة صفحة من ذاكرة التخزين المؤقت لميزة "التخزين المؤقت للصفحات"، تتم استعادتها من الذاكرة وليس من ذاكرة التخزين المؤقت لبروتوكول HTTP. نتيجةً لذلك، لا يتم أخذ توجيهات مثل Cache-Control: no-cache أو Cache-Control: max-age=0 في الاعتبار، ولا تتم إعادة التحقّق من المحتوى قبل عرض المحتوى للمستخدم.

لا تزال هذه تجربة أفضل للمستخدم، مع ذلك، فعمليات استعادة ميزة "التخزين المؤقت للصفحات" تتم بشكل فوري، ولأنّ الصفحات لا تظل في ذاكرة التخزين المؤقت لفترة طويلة جدًا، فمن غير المرجّح أن يكون المحتوى قديمًا. ومع ذلك، إذا كان المحتوى يتغيّر كل دقيقة، يمكنك استرجاع أي تعديلات باستخدام حدث pageshow على النحو الموضّح في القسم التالي.

تعديل البيانات القديمة أو الحسّاسة بعد استعادة ميزة "التخزين المؤقت للصفحات"

إذا كان موقعك الإلكتروني يحافظ على حالة المستخدم، وخاصةً أي معلومات حساسة عن المستخدم، يجب تعديل البيانات أو محوها بعد استعادة الصفحة من ذاكرة التخزين المؤقت لميزة "التخزين المؤقت للصفحات".

على سبيل المثال، إذا انتقل المستخدم إلى صفحة دفع ثم عدَّل سلة التسوّق، من المحتمل أن يعرض الانتقال إلى الوراء معلومات قديمة في حال استعادة صفحة قديمة من ميزة "التخزين المؤقت للصفحات".

مثال آخر أكثر أهمية هو إذا سجَّل المستخدم الخروج من موقع إلكتروني على جهاز كمبيوتر عام ثم نقر المستخدم التالي على زر الرجوع. من المحتمل أن يؤدي ذلك إلى الكشف عن بيانات خاصة افترض المستخدم أنّه تم محوها عند تسجيل الخروج.

لتجنُّب مثل هذه الحالات، من الأفضل تعديل الصفحة دائمًا بعد حدث 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();
  }
});

تتمتع إعادة التحميل بميزة الاحتفاظ بالسجل (للسماح بعمليات الانتقال للأمام)، ولكن قد تكون إعادة التوجيه أكثر ملاءمة في بعض الحالات.

استعادة الإعلانات والتخزين المؤقت للصفحات

قد يكون من المغري تجنُّب استخدام ميزة "التخزين المؤقت للصفحات" لعرض مجموعة جديدة من الإعلانات في كل عملية انتقال باستخدام ميزة "التخزين المؤقت للصفحات". ومع ذلك، ونظرًا للتأثير في الأداء، يمكن الالتفات إلى ما إذا كان هذا السلوك يؤدي إلى تحسين التفاعل مع الإعلان أم لا. قد يكون المستخدمون شاهدوا إعلانًا يريدون النقر عليه مرة أخرى، ولكنهم لم يتمكّنوا من ذلك من خلال إعادة تحميله من ذاكرة التخزين المؤقت للصفحات بدلاً من استعادته. يعد اختبار هذا السيناريو - من الناحية المثالية باستخدام اختبار A/B - أمرًا مهمًا قبل وضع افتراضات.

في المواقع الإلكترونية التي تريد إعادة تحميل الإعلانات فيها عند استعادة ميزة "التخزين المؤقت للصفحات"، بعد ذلك، تتم إعادة تحميل الإعلانات فقط في حدث pageshow عندما تكون قيمة event.persisted هي true، ما يتيح إجراء ذلك بدون التأثير في أداء الصفحة. يمكنك الرجوع إلى موفّر الإعلانات، ولكن إليك أحد الأمثلة على كيفية إجراء ذلك باستخدام علامة Google Publishing.

تجنُّب مراجع window.opener

في المتصفّحات القديمة، إذا تم فتح صفحة باستخدام الرمز window.open() من رابط يتضمّن target=_blank، بدون تحديد rel="noopener"، ستحتوي الصفحة الافتتاحية على مرجع إلى عنصر النافذة في الصفحة المفتوحة.

بالإضافة إلى تشكّل الصفحة خطرًا أمنيًا، لا يمكن وضع صفحة تحتوي على مرجع window.opener غير فارغ في ميزة "التخزين المؤقت للصفحات" بشكل آمن، لأنّ ذلك قد يؤدي إلى تعطّل أي صفحات تحاول الوصول إليها.

نتيجةً لذلك، من الأفضل تجنّب إنشاء مراجع window.opener. ويمكنك إجراء ذلك باستخدام rel="noopener" كلما أمكن ذلك (لاحظ أنّ هذا هو الإعداد التلقائي في جميع المتصفحات الحديثة). إذا كان موقعك الإلكتروني يتطلّب فتح نافذة والتحكّم فيها من خلال window.postMessage() أو الإشارة مباشرةً إلى عنصر النافذة، لن تكون النافذة المفتوحة أو أداة الفتح مؤهَّلتَين لاستخدام ميزة "التخزين المؤقت للصفحات".

إغلاق الاتصالات المفتوحة قبل انتقال المستخدم بعيدًا

كما ذكرنا سابقًا، عند وضع صفحة في ذاكرة التخزين المؤقت للصفحات، يتم إيقاف جميع مهام JavaScript المُجدوَلة مؤقتًا وتستأنفها عند سحب الصفحة من ذاكرة التخزين المؤقت.

إذا كانت مهام JavaScript المُجدوَلة هذه تصل إلى واجهات برمجة تطبيقات DOM فقط، أو واجهات برمجة تطبيقات أخرى معزولة في الصفحة الحالية فقط، لن يؤدي إيقاف هذه المهام مؤقتًا عندما تكون الصفحة غير مرئية للمستخدم إلى حدوث أي مشاكل.

ومع ذلك، إذا كانت هذه المهام مرتبطة بواجهات برمجة تطبيقات يمكن الوصول إليها أيضًا من صفحات أخرى في المصدر نفسه (على سبيل المثال: IndexedDB وWeb Locks وWebSockets)، قد يمثّل ذلك مشكلة لأنّ إيقاف هذه المهام مؤقتًا قد يؤدي إلى منع تشغيل الرموز في علامات التبويب الأخرى.

ونتيجةً لذلك، لن تحاول بعض المتصفحات وضع صفحة في ميزة "التخزين المؤقت للصفحات" في السيناريوهات التالية:

إذا كانت صفحتك تستخدم أيًا من واجهات برمجة التطبيقات هذه، ننصحك بشدة بإغلاق الروابط وإزالة المراقبين أو قطع اتصالهم أثناء حدث pagehide أو freeze. ويتيح ذلك للمتصفح الاحتفاظ بذاكرة التخزين المؤقت للصفحة بشكل آمن بدون المخاطرة بالتأثير في علامات التبويب المفتوحة الأخرى.

بعد ذلك، في حال استعادة الصفحة من ذاكرة التخزين المؤقت للصفحات، يمكنك إعادة فتح واجهات برمجة التطبيقات هذه أو إعادة الاتصال بها أثناء حدث pageshow أو resume.

يوضّح المثال التالي كيفية التأكّد من أنّ الصفحات التي تستخدم IndexedDB مؤهَّلة لاستخدام ميزة "التخزين المؤقت للصفحات" من خلال إغلاق اتصال مفتوح في أداة معالجة الحدث 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" في اختبار صفحاتك من أجل التأكّد من تحسينها لاستخدام ميزة "التخزين المؤقت للصفحات" وتحديد أي مشاكل قد تمنعها من تأهُّلها.

لاختبار صفحة:

  1. انتقِل إلى الصفحة في Chrome.
  2. في "أدوات مطوري البرامج"، انتقِل إلى التطبيق -> التخزين المؤقت للصفحات.
  3. انقر على الزر إجراء اختبار. بعد ذلك، تحاول أدوات مطوّري البرامج الابتعاد عن الموقع الإلكتروني والرجوع إليه لتحديد ما إذا كان من الممكن استعادة الصفحة من خلال ميزة "التخزين المؤقت للصفحات".
لوحة "التخزين المؤقت للصفحات" في "أدوات مطوّري البرامج"
لوحة التخزين المؤقت للصفحات في "أدوات مطوري البرامج".

إذا تم الاختبار بنجاح، ستعرض اللوحة رسالة "تمت الاستعادة من ميزة "التخزين المؤقت للصفحات".

الإبلاغ عن صفحة في "أدوات مطوري البرامج" تمت استعادتها بنجاح من ميزة "التخزين المؤقت للصفحات"
تمت استعادة صفحة بنجاح.

وإذا لم تنجح هذه العملية، ستوضّح اللوحة سبب ذلك. إذا كان السبب شيئًا يمكنك معالجته كمطوّر، تضع اللوحة علامة قابل للتنفيذ على السبب.

تعذُّر إعداد تقارير "أدوات مطوري البرامج" في استعادة صفحة من ذاكرة التخزين المؤقت للصفحات
تعذّر اختبار ميزة "التخزين المؤقت للصفحات" مع ظهور نتيجة قابلة للتنفيذ.

في هذا المثال، يؤدي استخدام أداة معالجة حدث unload إلى جعل الصفحة غير مؤهَّلة لاستخدام ميزة "التخزين المؤقت للصفحات". يمكنك حلّ هذه المشكلة من خلال التبديل من unload إلى استخدام pagehide:

الإجراءات الموصى بها
window.addEventListener('pagehide', ...);
الإجراءات غير المُوصى بها
window.addEventListener('unload', ...);

وقد أضاف Lighthouse 10.0 تدقيقًا إلى ذاكرة التخزين المؤقت الذي يجري اختبارًا مشابهًا. للحصول على مزيد من المعلومات، يمكنك الاطّلاع على مستندات تدقيق Bfcache.

كيفية تأثير ميزة "التخزين المؤقت للصفحات" في الإحصاءات وقياس الأداء

إذا كنت تستخدم أداة إحصاءات لقياس الزيارات إلى موقعك الإلكتروني، قد تلاحظ انخفاضًا في إجمالي عدد مشاهدات الصفحة على الويب التي يتم تسجيلها لأنّ Chrome يتيح ميزة "التخزين المؤقت للصفحات" لمزيد من المستخدمين.

في الواقع، من المحتمل أنّك تقلِّل عدد مرات مشاهدة الصفحة على الويب من المتصفّحات الأخرى التي تطبّق ميزة 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';
    });
  }
});

احسِب نسبة نتائج ميزة "التخزين المؤقت للصفحات" باستخدام عدد عمليات الانتقال back_forward وback_forward_cache عملية الانتقال.

من المهم أن تدرك أنّ هناك عددًا من السيناريوهات التي لا تستخدم فيها ميزة الانتقال من خلال ميزة "التخزين المؤقت للصفحات" ميزة "التخزين المؤقت للصفحات"، والتي تشمل خارج نطاق سيطرة مالكي المواقع الإلكترونية:

  • عندما يغلق المستخدم المتصفح ويبدأ تشغيله مرة أخرى
  • عندما يكرر المستخدم علامة تبويب
  • عندما يغلق المستخدم علامة تبويب ويعيد فتحها

في بعض هذه الحالات، قد تحتفظ بعض المتصفحات بنوع التنقل الأصلي، ومن ثم قد يعرض النوع back_forward على الرغم من عدم إدراج هذا النوع من عمليات التنقّل.

وحتى في حال عدم استخدام هذه الاستثناءات، سيتم تجاهل ذاكرة التخزين المؤقت للصفحات بعد مرور فترة بهدف الحفاظ على الذاكرة.

لذلك، من غير المتوقّع أن يحصل مالكو المواقع الإلكترونية على نسبة 100% من نتائج ميزة "التخزين المؤقت للصفحات" في جميع عمليات التنقّل على back_forward. مع ذلك، قد يكون قياس نسبة عرضها مفيدًا لتحديد الصفحات التي تمنع فيها الصفحة نفسها استخدام ميزة "التخزين المؤقت للصفحات" لنسبة عالية من عمليات الانتقال ذهابًا وإيابًا.

أضاف فريق Chrome واجهة برمجة التطبيقات NotRestoredReasons للمساعدة في التعرّف على أسباب عدم استخدام ميزة "التخزين المؤقت للصفحات" في الصفحات، حتى يتمكّن المطوّرون من تحسين معدّلات نتائج ميزة "التخزين المؤقت للصفحات". وأضاف فريق Chrome أيضًا أنواع التنقّل إلى نظام التشغيل CrUX ليتمكّن من الاطّلاع على عدد عمليات التنقّل في ذاكرة التخزين المؤقت للصفحات حتى بدون قياسها بنفسك.

قياس الأداء

يمكن أن تؤثر ميزة "التخزين المؤقت للصفحات" أيضًا سلبًا في مقاييس الأداء التي يتم جمعها في الحقل، لا سيّما المقاييس التي تقيس أوقات تحميل الصفحات.

نظرًا لأنّ عمليات التنقّل باستخدام ميزة "التخزين المؤقت للصفحات" تقوم باستعادة صفحة حالية بدلاً من بدء تحميل صفحة جديدة، سينخفض إجمالي عدد عمليات تحميل الصفحات التي تم جمعها عندما تكون ميزة "التخزين المؤقت للصفحات" مُفعَّلة. مع ذلك، من المهم جدًا أن يتم على الأرجح تحميل الصفحات التي يتم تحميلها من خلال عمليات استعادة من خلال bfcache، وهي إحدى أسرع تحميلات الصفحات ضمن مجموعة البيانات لديك. ويرجع ذلك إلى أنّ عمليات الانتقال للخلف وللأمام، حسب تعريفها، هي زيارات متكرّرة، كما أنّ عمليات تحميل الصفحات المتكرّرة تكون بشكل عام أسرع من عمليات تحميل الصفحات التي يجريها الزائرون للمرة الأولى (بسبب التخزين المؤقت باستخدام بروتوكول HTTP، كما ذكرنا سابقًا).

والنتيجة هي عدد أقل من عمليات التحميل السريعة للصفحات في مجموعة البيانات، مما قد يؤدي على الأرجح إلى تحريف التوزيع بشكل أبطأ - على الرغم من حقيقة أن الأداء الذي تم تجربته من قبل المستخدم قد تحسن!

هناك عدة طرق للتعامل مع هذه المشكلة. الأولى هي إضافة تعليق توضيحي إلى جميع مقاييس تحميل الصفحات باستخدام نوع التنقّل الخاص بها: navigate أو reload أو back_forward أو prerender. يتيح لك هذا مواصلة مراقبة الأداء ضمن أنواع التنقل هذه، حتى إذا كان التوزيع الكلي يحيد بشكل سلبي. ننصحك باستخدام هذا النهج مع مقاييس تحميل الصفحات التي لا تركّز على المستخدم، مثل Time to First بايت (TTFB).

بالنسبة إلى المقاييس التي تركّز على المستخدم مثل مؤشرات أداء الويب الأساسية، يكون الخيار الأفضل هو الإبلاغ عن قيمة تمثّل ما يمر به المستخدم بدقة أكبر.

التأثير في "مؤشرات أداء الويب الأساسية"

تقيس مؤشرات أداء الويب الأساسية تجربة المستخدم على صفحة الويب على مستوى مجموعة متنوعة من السمات (سرعة التحميل والتفاعل والثبات البصري). وبما أنّ تجربة المستخدمين لميزة "التخزين المؤقت للصفحات" تتم استعادة البيانات بشكل أسرع مقارنةً بتحميل الصفحات بالكامل، من المهم أن تعكس مقاييس "مؤشرات أداء الويب الأساسية" ذلك. وفي نهاية الأمر، لا يهتم المستخدم بما إذا تم تفعيل ميزة "التخزين المؤقت للصفحات" أم لا، بل يهمه أن يكون التنقّل سريعًا.

إنّ الأدوات التي تجمع مقاييس "مؤشرات أداء الويب الأساسية" وتنشئ تقريرًا عنها، مثل تقرير تجربة المستخدم في Chrome، تتعامل مع عمليات استعادة ميزة "التخزين المؤقت للصفحات" على أنّها زيارات منفصلة للصفحات في مجموعة البيانات. وعلى الرغم من عدم توفّر واجهات برمجة تطبيقات مخصّصة لأداء الويب لقياس هذه المقاييس بعد استعادة ميزة "التخزين المؤقت للصفحات"، يمكنك تقريب القيم باستخدام واجهات برمجة تطبيقات الويب الحالية:

  • بالنسبة إلى سرعة عرض أكبر محتوى مرئي (LCP)، استخدِم علامة دلتا بين الطابع الزمني للحدث pageshow والطابع الزمني للإطار الملوَّن التالي، لأنّه سيتم عرض جميع العناصر في الإطار في الوقت نفسه. وفي حال استعادة ميزة "التخزين المؤقت للصفحات"، يكون مقياس LCP وFCP متماثلاً.
  • في حقل مدى استجابة الصفحة لتفاعلات المستخدم (INP)، واصِل استخدام أداة "مراقبة الأداء" الحالية، ولكن أعِد ضبط قيمة INP الحالية إلى 0.
  • بالنسبة إلى متغيّرات التصميم التراكمية (CLS)، يمكنك مواصلة استخدام "أداة مراقبة الأداء" الحالية، ولكن أعِد ضبط قيمة متغيّرات التصميم التراكمية الحالية إلى 0.

لمزيد من التفاصيل حول كيفية تأثير ميزة "التخزين المؤقت للصفحات" في كل مقياس، يمكنك الاطّلاع على صفحات أدلّة المقاييس الفردية في "مؤشرات أداء الويب الأساسية". للاطّلاع على مثال محدّد عن كيفية تنفيذ نُسخ Bfcache لهذه المقاييس، يمكنك الرجوع إلى مقالة PR لإضافتها إلى مكتبة JavaScript لأحرف الويب.

إنّ مكتبة JavaScript لمكوّنات الويب تتيح عمليات استعادة ميزة "التخزين المؤقت للصفحات" في المقاييس التي تسجّلها تلك المكتبة.

مراجع إضافية