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

تاريخ النشر: 25 مايو 2023، تاريخ آخر تعديل: 25 مارس 2025

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

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

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

تتضمّن جميع المتصفّحات الرئيسية ميزة "التخزين المؤقت للصفحات"، بما في ذلك Chrome منذ الإصدار 96 وFirefox وSafari.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ميزة "التخزين المؤقت للصفحات" وإطارات iframe

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

ومع ذلك، عند استعادة الإطار الرئيسي من ذاكرة التخزين المؤقت للصفحات (bfcache)، ستتم استعادة إطارات iframe المضمّنة كما كانت عندما دخلت الصفحة إلى ذاكرة التخزين المؤقت للصفحات.

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

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

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

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

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

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

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

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

يتم تنشيط الحدث pageshow مباشرةً بعد الحدث load عند تحميل الصفحة في البداية وفي كل مرة تتم فيها استعادة الصفحة من ميزة "التخزين المؤقت للصفحات". يحتوي الحدث pageshow على السمة persisted التي تكون قيمتها true إذا تمت استعادة الصفحة من ذاكرة التخزين المؤقت للصفحات (bfcache)، و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.');
  }
});

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

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

مراقبة وقت دخول الصفحة إلى ذاكرة التخزين المؤقت للخلف والأمام

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

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

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

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

توضّح الأقسام التالية أفضل الممارسات لزيادة احتمالية أن يتمكّن المتصفّح من تخزين صفحاتك مؤقتًا.

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

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

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

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

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

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

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

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

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

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

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

Permissions-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. يتم استخدامها للموارد التي تحتوي على معلومات حساسة عن المستخدمين، مثل الصفحات المحمية بكلمة مرور.

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

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

تعديل البيانات القديمة أو الحسّاسة بعد استعادة 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();
  }
});

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

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

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

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

تجنُّب مراجع 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', ...);

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

تأثير bfcache في قياس الأداء والإحصاءات

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

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

لتضمين عمليات الاستعادة من ميزة "التخزين المؤقت للصفحات" في عدد مشاهدات صفحات الويب، اضبط متتبِّعات الحدث pageshow وتحقّق من السمة persisted.

يوضّح المثال التالي كيفية إجراء ذلك باستخدام "إحصاءات Google". من المحتمل أنّ أدوات الإحصاءات الأخرى تستخدم منطقًا مشابهًا:

// Send a pageview when the page is first loaded.
// This happens by default just by loading gtag
gtag('config', 'TAG_ID');

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.
// To do this disable the default pageview so you can manually send it
// supplemented with the additional detail.
gtag('config', 'TAG_ID', { send_page_view: false });
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 أيضًا أنواع التنقّل إلى تقرير تجربة المستخدم على Chrome، ما يتيح الاطّلاع على عدد عمليات التنقّل باستخدام ميزة "التخزين المؤقت للصفحات" حتى بدون قياسها بنفسك.

قياس الأداء

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

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

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

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

بالنسبة إلى المقاييس التي تركّز على المستخدم، مثل Core Web Vitals، من الأفضل عرض قيمة تمثّل بشكل أكثر دقة تجربة المستخدم.

التأثير في Core Web Vitals

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

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

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

للحصول على مزيد من التفاصيل حول تأثير ميزة "التخزين المؤقت للصفحات" على كل مقياس، اطّلِع على صفحات أدلة المقاييس الفردية لمقاييس Core Web Vitals. للحصول على مثال محدّد حول كيفية تنفيذ إصدارات bfcache من هذه المقاييس، يمكنك الرجوع إلى طلب السحب الذي يضيفها إلى مكتبة web-vitals JavaScript.

تتيح مكتبة JavaScript web-vitals عمليات الاستعادة من ذاكرة التخزين المؤقت للصفحات في المقاييس التي تعرضها.

موارد إضافية