العودة إلى المدونة

سكربت التحليلات الخاص بك يُعطِّل على الأرجح ذاكرة التخزين المؤقت للرجوع/التقدّم

تجعل ذاكرة التخزين المؤقت للرجوع/التقدّم عمليات التنقّل بزر الرجوع شبه فورية، لكن مستمعًا واحدًا من نوع unload يُعطِّلها للصفحة بأكملها. وسكربتات التتبّع هي المتّهم المعتاد — وأصبح CrUX الآن يقيس حجم الضرر.

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

إنّ bfcache هي تحسين يقوم به المتصفّح يحتفظ بلقطة كاملة للصفحة في الذاكرة — بما في ذلك كومة JavaScript — عندما ينتقل المستخدم بعيدًا عنها. اضغط زرّ الرجوع فيستعيد المتصفّح تلك اللقطة ويستأنف التنفيذ، منتجًا تحميلًا شبه فوري دون أي طلب شبكي. وتشكّل عمليات التنقّل بالرجوع والتقدّم نسبة تُقدَّر بـ 10–20% من إجمالي عمليات التنقّل، لذا فهذه ليست حالة هامشية.

مستمع واحد يُقصي الصفحة بأكملها

أهلية bfcache هشّة بحكم التصميم. فالمتصفّح لن يُجمّد صفحةً سجّلت مستمعًا لحدث unload، لأنّ unload يعني ضمنيًا أنّ الصفحة تتوقّع أن يجري تفكيكها. وعلى الحاسوب المكتبي، يجعل كلٌّ من Chrome وFirefox أي صفحة فيها مستمع unload غير مؤهّلة لـ bfcache — بلا استثناءات ولا أهلية جزئية.

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

لم يعد beforeunload مُقصِيًا في المتصفّحات الحديثة، لكنّه غير موثوق ويبقى من الأفضل تجنّبه ما لم تكن لدى المستخدم تغييرات غير محفوظة.

سكربتات التتبّع هي المُخالِف المعتاد

حدث unload هو المكان الكلاسيكي لإطلاق منارة (beacon) أخيرة — لتفريغ جلسة، أو إرسال حدث "أُغلقت الصفحة" — لذا تلجأ إليه سكربتات تتبّع السلوك والإعلانات باستمرار.

يسجّل ملف fbevents.js من Facebook معالِجًا لـ unload، ويظهر على ما يقارب 9% من إجمالي صفحات الويب وفقًا لـ HTTP Archive. أمّا وسم PayPal فيحقن إطارًا (iframe) يضيف حدث unload، مُعطِّلًا bfcache في كثير من مسارات الدفع. وقد فعلت سكربتات الإطارات الفرعية مثل hCaptcha الشيء نفسه. ولا يتطلّب أيٌّ من هذه تغييرًا في شيفرتك أنت لكي يبدأ في تكليفك ثمنًا — يكفي أن يدفع المزوّد تحديثًا.

أصبح CrUX الآن يُظهر لك الفاتورة

كان هذا فيما مضى غير مرئي في بيانات الميدان. فمنذ مجموعة بيانات مارس 2024، أصبح تقرير تجربة مستخدمي Chrome (CrUX) يقدّم تفصيلًا لـ navigation_types — بما في ذلك نسبة الزيارات التي قُدِّمت من ذاكرة التخزين المؤقت للرجوع/التقدّم — حتى تتمكّن من رؤية كم من المستخدمين الحقيقيين يفوتهم المسار الفوري.

والارتباط صارخ. وجد تحليل CrUX علاقة إحصائية قوية (ρ=0.87) بين ارتفاع نسبة back_forward_cache وبين instant_lcp_density — أي حصّة عمليات التحميل التي يكون فيها LCP أقل من 200 ms. وبعد أن رفع تحديث Google في مارس 2026 من وزن ترتيب LCP وINP وCLS، أصبح حجب bfcache الذي يُلحقه الموقع بنفسه عيبًا قابلًا للقياس عند المئين الخامس والسبعين، لا مجرّد خطأ تقريب.

كشفه وإصلاحه

افتح DevTools، واذهب إلى Application ← Back/forward cache، ثم انقر Run Test. سيسرد Chrome كل سبب حاجب، بما في ذلك معالِجات unload التي أضافتها أطراف خارجية.

ولكشف عمليات استعادة bfcache في شيفرتك أنت، لا تستخدم unload أبدًا. استخدم pageshow وتحقّق من persisted:

window.addEventListener('pageshow', (event) => {
  if (event.persisted) {
    // restored from bfcache — no fresh page load fired
  }
})

ولمنع الأطراف الخارجية من إقصائك، عيِّن ترويسة استجابة تمنع مستمعي unload منعًا تامًّا:

Permissions-Policy: unload=()

يُبطل هذا مفعول معالِجات unload القادمة من أي سكربت — وسوم المزوّدين، أو الإضافات، أو حتى شيفرتك القديمة — فتبقى الصفحة مؤهّلة لـ bfcache بغضّ النظر عمّا يُحمَّل.

أداة التتبّع التي لا تمسّها أبدًا

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

fetch('/collect', {
  method: 'POST',
  keepalive: true,
  body: JSON.stringify({ site_id, path: location.pathname })
})

وعندما تحتاج أداة التتبّع إلى الاستجابة لانتقال صفحة إلى الخلفية، فإنّ الإشارة الصحيحة هي visibilitychange أو pagehide، وكلاهما يُطلَق دون أن يجعل الصفحة غير مؤهّلة لـ bfcache. وأداة تتبّع Monoid يبلغ حجمها نحو 2 KB، ولا تضع أي ملفّات تعريف ارتباط، وتربط history.pushState لتغييرات مسارات تطبيقات الصفحة الواحدة (SPA) بدلًا من دورة حياة الصفحة — لذا ليس لديها مستمع unload لتسجّله، ولا أي شيء كي يُعطِّل ذاكرة التخزين المؤقت للرجوع/التقدّم لديك.

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

المصادر

Comments

Loading comments…