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

ميزة "التخزين المؤقت للصفحات" (أو 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 المضمّنة كما كانت عندما دخلت الصفحة إلى ذاكرة التخزين المؤقت للصفحات (bfcache).

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

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

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

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

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

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

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

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

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

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

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

عدم استخدام الحدث 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.

يُرجى العِلم أنّه عند استعادة صفحة من ذاكرة التخزين المؤقت للصفحات (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();
  }
});

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

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

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

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

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

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

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

قياس الأداء

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

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

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

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

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

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

تقيس مؤشرات 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 من هذه المقاييس، يُرجى الرجوع إلى طلب السحب الذي يضيفها إلى مكتبة JavaScript الخاصة بمقاييس Web Vitals.

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

موارد إضافية