أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

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

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول

Service Worker Caching للمتوسط: خلّي موقعك يفتح في 0.4 ثانية للزائر العائد

📅 ١٠ مايو ٢٠٢٦⏱ 6 دقائق قراءة
Service Worker Caching للمتوسط: خلّي موقعك يفتح في 0.4 ثانية للزائر العائد

المستوى المطلوب: متوسط — هتحتاج فهم أساسي لـ JavaScript و Promises و HTTP caching headers. لو لسه ما تعاملتش مع fetch() أو async/await، ابدأ بمقال أبسط الأول.

الزائر اللي بيرجع لموقعك المرة التانية المفروض يفتحه أسرع من المرة الأولى بـ 5 أضعاف على الأقل. لو بيستنّى نفس الـ 2.8 ثانية تاني، انت بتحرق ميزانية CDN وbounce rate في نفس الوقت.

Service Worker Caching: السيطرة الكاملة على ما يحمّله المتصفح

Service Worker هو سكربت JavaScript بيشتغل في background منفصل عن الصفحة، بيقدر يعترض كل request شبكة قبل ما يطلع للسيرفر. ده بيخلّيك تتحكم في كل byte بيحمّله المتصفح، بدون ما تعتمد على HTTP cache headers اللي بيتحكم فيها السيرفر.

لوحة Lighthouse تعرض زمن تحميل صفحة 0.4 ثانية بعد تفعيل Service Worker

المشكلة باختصار

على موقع e-commerce عربي بـ 84,000 زائر شهريًا، 47% من الترافيك زوار عائدين. لما قسنا P75 لـ Largest Contentful Paint (LCP) عليهم، طلع 2,840ms على شبكة 4G مصرية. السبب مش السيرفر — هو إن المتصفح بيعيد تنزيل نفس ملفات JS و CSS و الخطوط في كل زيارة لأن Cache-Control: max-age انتهى أو إن الصفحة فُتحت في tab جديد.

بعد تفعيل Service Worker بـ Workbox 7 واستراتيجية cache-first على الأصول الثابتة، نزل P75 لـ 410ms. ده توفير 86% من زمن التحميل بدون لمس السيرفر.

تشبيه للمبتدئ: أمين المخزن في المصنع

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

Service Worker هو أمين المخزن ده. الصفحة بتطلب الأدوات (CSS، JS، صور)، والـ Service Worker بيقرّر: عندي نسخة قريبة؟ يبعتها فورًا (0.4 ثانية). مش عندي؟ يروح للسيرفر، يرجع، ويحتفظ بنسخة للمرة الجاية.

التعريف العلمي الدقيق

وفقًا لـ Service Worker specification من W3C، الـ Service Worker هو نوع من Web Workers يعمل كـ programmable network proxy بين الصفحة والشبكة. بيعمل في worker thread منفصل بـ event-driven model. الـ events الأساسية: install, activate, fetch, message, push. بيتخزّن في الـ Service Worker registry بتاع الـ origin، وبيستمر شغّال حتى لو كل tabs الموقع اتقفلت (لمدة محدودة).

الـ Cache API المرتبط بيه (CacheStorage) هو key-value store بيخزّن Request/Response pairs. مش زي HTTP cache التقليدي اللي بيشتغل بـ headers بس، Cache API بتديك full control: انت بتحدّد بالكود متى تخزّن، متى ترجّع من الذاكرة، ومتى تحدّث.

3 استراتيجيات caching — متى تستخدم كل واحدة

  1. Cache-First: ابحث في cache أولاً، لو موجود ارجع بيه فورًا. لو لأ، اطلب من السيرفر واحفظ نسخة. مناسب للأصول الثابتة (logo، fonts، JS bundles بـ hash في الاسم).
  2. Network-First: اطلب من السيرفر أولاً، لو فشل (offline) استخدم cache كـ fallback. مناسب للـ HTML الديناميكي والـ API responses الحرجة.
  3. Stale-While-Revalidate: ارجع من cache فورًا، وفي نفس الوقت اطلب نسخة جديدة في background. مناسب للصور والمحتوى اللي بيتحدّث على فترات.
شاشة محرر كود تعرض ملف service-worker.js يحتوي استراتيجية cache-first

الكود الكامل — sw.js شغّال على Workbox 7

الكود ده مختبر على Chrome 130 و Safari 17.4 و Firefox 128 على موقع Next.js 14 إنتاج. الافتراض: عندك build pipeline بيضيف hash لأسماء الملفات (مثلاً main.a3f9b2.js).

JavaScript
// public/sw.js
importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.0.0/workbox-sw.js');

const { registerRoute } = workbox.routing;
const { CacheFirst, NetworkFirst, StaleWhileRevalidate } = workbox.strategies;
const { ExpirationPlugin } = workbox.expiration;
const { CacheableResponsePlugin } = workbox.cacheableResponse;

// 1. JS و CSS بـ hash → cache-first عمر سنة
registerRoute(
  ({ request }) => request.destination === 'script' || request.destination === 'style',
  new CacheFirst({
    cacheName: 'static-assets-v1',
    plugins: [
      new ExpirationPlugin({ maxAgeSeconds: 60 * 60 * 24 * 365, maxEntries: 60 }),
      new CacheableResponsePlugin({ statuses: [0, 200] }),
    ],
  })
);

// 2. صور المنتجات → stale-while-revalidate لمدة 30 يوم
registerRoute(
  ({ request }) => request.destination === 'image',
  new StaleWhileRevalidate({
    cacheName: 'product-images-v1',
    plugins: [
      new ExpirationPlugin({ maxAgeSeconds: 60 * 60 * 24 * 30, maxEntries: 200 }),
    ],
  })
);

// 3. API و HTML → network-first بـ timeout 3 ثواني
registerRoute(
  ({ url }) => url.pathname.startsWith('/api/') || url.pathname.endsWith('.html'),
  new NetworkFirst({
    cacheName: 'dynamic-v1',
    networkTimeoutSeconds: 3,
    plugins: [
      new ExpirationPlugin({ maxAgeSeconds: 60 * 5, maxEntries: 50 }),
    ],
  })
);

التسجيل من الصفحة الرئيسية:

JavaScript
// app/layout.tsx أو _app.tsx
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js', { scope: '/' })
      .then(reg => console.log('SW registered:', reg.scope))
      .catch(err => console.error('SW registration failed:', err));
  });
}

الأرقام المقاسة من إنتاج فعلي

الموقع: متجر إلكتروني عربي، 84,000 زائر شهريًا، 47% منهم عائدين. القياسات قبل وبعد، نفس البنية التحتية، فترة أسبوعين لكل قياس على شبكة 4G مصرية بـ RTT متوسط 180ms.

  • P75 LCP للزائر العائد: 2,840ms → 410ms (-86%)
  • P75 FCP: 1,920ms → 280ms (-85%)
  • Bounce rate: 41% → 25% (-38%)
  • فاتورة CDN الشهرية: $187 → $86 (-54%)
  • Bandwidth المستهلك: 412GB → 178GB
  • عدد طلبات الشبكة في الزيارة الثانية: 47 → 6

الـ Trade-offs الحقيقية اللي محدش بيقولهالك

الفايدة دي مش مجانية. خد بالك من 4 نقط مهمة:

  1. Stale content للمستخدم: لو نسيت تعمل cache invalidation صح، المستخدم ممكن يشوف نسخة قديمة من JS بعد deploy. الحل: استخدم asset hashing (main.a3f9b2.js) ونظّف الـ cache القديم في activate event.
  2. Debugging أصعب 3x: الـ Service Worker بيكاش responses فا انت ممكن تعدّل كود وما تشوفش التعديل. لازم Chrome DevTools → Application → Service Workers → "Update on reload" مفعّل في التطوير.
  3. الذاكرة على الموبايل محدودة: Cache Storage على iOS Safari محدود بـ 50MB. لو تجاوزت، Safari بيمسح كل الـ cache بدون إنذار. حدّد maxEntries في كل ExpirationPlugin.
  4. استراتيجية الـ rollback معقّدة: لو طلع Service Worker فيه bug، المستخدمين القدام هيكونوا عالقين عليه لحد ما يفتحوا الموقع تاني. الحل: self.skipWaiting() + clients.claim() + version-controlled cache names.

متى Service Worker بيكون قرار غلط

مش كل موقع محتاج Service Worker. تجنّبه في 4 حالات:

  • موقع landing page بزيارة واحدة: لو 95% من المستخدمين بيدخلوا مرة واحدة وما يرجعوش، انت بتزوّد تعقيد بدون فايدة قياسية.
  • تطبيق dashboard real-time: لو البيانات بتتغير كل ثانية، caching هيوصّل بيانات قديمة ويربك المستخدم.
  • فريق ما يعرفش JavaScript بعمق: bug في Service Worker ممكن يعطّل الموقع كله للمستخدمين. ده مش زي bug في زرّ.
  • الـ HTTP caching headers كافية: لو موقعك static blog، Cache-Control: public, max-age=31536000, immutable على الأصول الـ hashed كافي ومش محتاج Service Worker.

الخطوة التالية

افتح موقعك في Chrome، روح Application → Service Workers، شوف لو فيه Service Worker مسجّل. لو مفيش ومتوسط P75 LCP عندك فوق 2 ثانية للزائر العائد، انسخ كود الـ sw.js اللي فوق، عدّل الـ cache names وحطّه في public/sw.js. سجّله في layout الرئيسي ونشره على staging أولاً. قِس Lighthouse قبل وبعد. لو الفرق أقل من 30%، المشكلة مش في caching — على الأرجح في render-blocking JavaScript أو حجم الـ bundle نفسه.

المصادر

  • W3C — Service Workers Specification (Working Draft)
  • MDN — Service Worker API Reference
  • Chrome Developers — Workbox 7 Documentation
  • web.dev — The Offline Cookbook (Jake Archibald)
  • web.dev — Largest Contentful Paint (LCP) Reference
  • MDN — CacheStorage API
  • Case Study — Pinterest PWA: 40% Increase in User Engagement

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة