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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

bfcache وإطارات iframe

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

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

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

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

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

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

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

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

مراقبة الحالات التي تتم فيها استعادة صفحة من bfcache

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Permission-Policy: unload=()

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

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

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

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

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

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

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

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

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

أدوات مطوّري البرامج التي تُبلغ عن استعادة صفحة بنجاح من خلال ميزة bfcache
صفحة تمّت استعادتها بنجاح

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

أدوات مطوري البرامج تُبلغ عن تعذُّر استعادة صفحة من bfcache
اختبار bfcache تعذّر إكماله مع نتيجة قابلة للتنفيذ:

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

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

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

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

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

في بعض هذه الحالات، قد تحافظ بعض المتصفّحات على نوع التنقّل الأصلي، وبالتالي قد تعرض نوعًا من back_forward على الرغم من أنّ هذه ليست عمليات تنقّل للخلف/للأمام.

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

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

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

قياس الأداء

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

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

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

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

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

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

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

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

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

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

توفّر مكتبة JavaScript الخاصة بخدمة web-vitals إمكانية استعادة bfcache في المقاييس التي تسجّلها.

موارد إضافية