لماذا تطبيقك بطيء (وكيفية إصلاح ذلك)
هل سبق لك أن انتظرت حتى يعاد رسم الواجهة بعد النقر؟ أو هل لاحظت أن الخادم يستجيب لنفس الطلب عدة مرات متتالية؟ مألوف؟ إذن هذه المقالة لك. التخزين المؤقت للبيانات ليس مجرد "ممارسة جيدة"، بل هو مهارة أساسية لأي مطور TypeScript يريد أن يجعل تطبيقه يطير بدلاً من الزحف.
اليوم سنشرح كيفية تخزين البيانات مؤقتًا بشكل صحيح في TypeScript: من cache بسيط في الذاكرة على الواجهة الأمامية إلى استراتيجيات متقدمة مع TTL و Redis على الواجهة الخلفية. ستحصل على قطع كود جاهزة يمكنك إدراجها في مشروعك اليوم.
ما هو التخزين المؤقت ولماذا هو مطلوب في TypeScript؟
التخزين المؤقت هو تقنية تخزين البيانات المستخدمة بشكل متكرر مؤقتًا في مخزن سريع. بدلاً من الذهاب إلى قاعدة البيانات أو الخادم البعيد في كل مرة، نحفظ نتيجة الطلب الأول ونقدمها عند الطلبات المتكررة.
المزايا واضحة:
- تقليل زمن الاستجابة (latency) - يحصل المستخدم على البيانات بالميلي ثانية
- تقليل الحمل على الخادم وقاعدة البيانات
- توفير النطاق الترددي والموارد
- إمكانية العمل دون اتصال (للأمامية)
في TypeScript، بفضل نظام الأنواع، يمكننا كتابة تخزين مؤقت آمن وقابل للتنبؤ لن يتعطل في وقت التشغيل. دعنا نرى كيف نفعل ذلك.
استراتيجيات التخزين المؤقت: اختيار النهج الصحيح
قبل كتابة الكود، تحتاج إلى فهم الاستراتيجية التي ستستخدمها. يعتمد على ذلك مدى فعالية الحل الخاص بك.
1. In-Memory Cache (ذاكرة التخزين المؤقت)
الخيار الأبسط والأسرع. يتم تخزين البيانات في متغير أو Map أو كائن. مثالي للواجهة الأمامية وتطبيقات Node.js الصغيرة.
العيب: تُفقد البيانات عند إعادة تحميل الصفحة أو إعادة تشغيل الخادم.
2. LocalStorage / SessionStorage (ذاكرة التخزين المؤقت في المتصفح)
مناسب للواجهة الأمامية عندما تحتاج إلى حفظ البيانات بين الجلسات. مثالي لإعدادات المستخدم والرموز المميزة وتخزين استجابات API مؤقتًا.
العيب: وصول متزامن، حد للحجم (5-10 ميغابايت).
3. Redis (ذاكرة التخزين المؤقت على الخادم)
المعيار الصناعي للواجهة الخلفية. سريع وموثوق ويدعم TTL وهياكل البيانات المعقدة. يعمل بشكل ممتاز مع Node.js عبر مكتبة ioredis.
العيب: يتطلب خدمة منفصلة (خادم Redis).
4. Service Worker + Cache API (PWA)
ذاكرة تخزين مؤقت متقدمة لتطبيقات الويب التقدمية. يسمح باعتراض طلبات الشبكة وتقديم استجابات مخزنة مؤقتًا. مثالي لوضع عدم الاتصال.
كتابة ذاكرة تخزين مؤقت في TypeScript: من البسيط إلى المعقد
الآن ننتقل إلى التطبيق العملي. سأعرض عدة تطبيقات، من الأساسي إلى المتقدم، باستخدام TypeScript generics.
ذاكرة تخزين مؤقت بسيطة في الذاكرة مع TTL
لنبدأ بالكلاسيكية - ذاكرة تخزين مؤقت في الذاكرة مع حذف تلقائي للإدخالات القديمة.
// cache.tsinterface CacheEntry<T> { data: T; expiry: number; // timestamp بالميلي ثانية}
class SimpleCache<T> { private store = new Map<string, CacheEntry<T>>();
constructor(private defaultTTL: number = 60000) {} // 60 ثانية افتراضيًا
set(key: string, data: T, ttl?: number): void { const expiry = Date.now() + (ttl ?? this.defaultTTL); this.store.set(key, { data, expiry }); }
get(key: string): T | undefined { const entry = this.store.get(key); if (!entry) return undefined; if (Date.now() > entry.expiry) { this.store.delete(key); return undefined; // منتهي الصلاحية } return entry.data; }
has(key: string): boolean { return this.get(key) !== undefined; }
clear(): void {