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

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

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

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

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

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

أساسيات Bfcache

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

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

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

اطلع على هذا الفيديو عن bfcache أثناء التنفيذ لفهم السرعة التي يمكن أن تقدمها في عمليات التنقل:

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

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

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

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

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

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

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

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

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

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

bfcache وإطارات iframe

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

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

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

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

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

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

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

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

الملاحظة عند استعادة صفحة من bfcache

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

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

ملاحظة عند إدخال إحدى الصفحات لميزة bfcache

يتم تنشيط حدث 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

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

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

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

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

يمثّل حدث unload مشكلة في المتصفّحات لأنّه يسبق تخزين bfcache وأنّ العديد من الصفحات على الإنترنت تعمل بموجب افتراض (معقول) بأنّ الصفحة لن تظلّ متوفّرة بعد إطلاق حدث 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" ضمان عدم إضافتها باستخدام سياسة الأذونات.

Permission-Policy: unload=()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

في هذا المثال، يؤدي استخدام أداة معالجة حدث 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');
  }
});

قياس نسبة نتائج Bfcache

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

// Send a navigation_type when the page is first loaded.
gtag('event', 'page_view', {
   'navigation_type': performance.getEntriesByType('navigation')[0].type;
});

window.addEventListener('pageshow', (event) => {
  if (event.persisted) {
    // Send another pageview if the page is restored from bfcache.
    gtag('event', 'page_view', {
      'navigation_type': 'back_forward_cache';
    });
  }
});

احسب نسبة نتائج Bfcache باستخدام أعداد التنقّل في back_forward وback_forward_cache والتنقّل.

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

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

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

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

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

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

قياس الأداء

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

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

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

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

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

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

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

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

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

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

تتيح web-vitals مكتبة JavaScript ميزة استعادة bfcache في المقاييس الواردة في التقارير.

موارد إضافية