الرئيسيةمن أناالدوراتالمدونةسوق الأوامرالمناهج والباقاتالشركاء

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

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

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • المناهج والباقات
  • سوق الأوامر
  • المدونة

الدعم

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

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

الرئيسيةالدوراتالمناهجالمدونةالدخول
البرمجة بالعربي

الفرق بين Debounce وThrottle: تحكّم في زحمة الأحداث بسطرين كود

متوسط1 أغسطس 20264 دقائق قراءة
الفرق بين Debounce وThrottle: تحكّم في زحمة الأحداث بسطرين كود

هذا المقال يتطلب مستوى متوسط. لو لسه مبتدئ، كمّل معايا؛ هنبدأ بمثال بسيط جدًا قبل الجزء التقني.

الفرق بين Debounce وThrottle: تحكّم في زحمة الأحداث بسطرين كود

لو صندوق البحث عندك بيبعت طلب للسيرفر مع كل حرف بيكتبه المستخدم، إنت بتضيّع أكثر من 90% من الطلبات على الفاضي. الحل مش سيرفر أقوى، الحل سطرين كود. المقال يوريك الفرق بين Debounce وThrottle، وإمتى تستخدم كل واحد بالظبط، بكود شغّال وأرقام مقاسة.

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

أحداث زي الكتابة (input) والتمرير (scroll) وتغيير حجم النافذة (resize) بتتنفّذ عشرات المرات في الثانية الواحدة. لو ربطت كل نبضة منها بعملية غالية — طلب شبكة، حساب معقّد، إعادة رسم — التطبيق بيغرق في شغل هو أصلًا مش محتاجه. النتيجة: بطء، وحمل زيادة على السيرفر، وفاتورة أعلى.

الأول مثال بسيط: المصعد وموظف الحضور

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

Throttle زي موظف بيسجّل الحضور مرة كل دقيقة بالظبط: مهما دخل ناس كتير في الدقيقة دي، هو بيسجّل تسجيلة واحدة، وبعدها يقفل لحد ما تعدّي الدقيقة. يعني تنفيذ منتظم بإيقاع ثابت، مش استنى-لحد-ما-يهدأ.

نفس الكلام بشكل علمي ودقيق

Debounce: أجّل تنفيذ الدالة لحد ما يعدّي فترة زمنية X من غير ما يحصل أي حدث جديد. كل حدث جديد بيلغي المؤقّت السابق ويبدأ عدّ من جديد. مناسب لـ "نفّذ لما المستخدم يخلّص".

Throttle: اسمح للدالة تتنفّذ مرة واحدة بحد أقصى كل فترة X، وتجاهل أي أحداث بتيجي جوه الفترة دي. مناسب لـ "نفّذ باستمرار لكن بمعدّل محكوم".

كود شغّال

JavaScript
// Debounce: ينفّذ بعد ما تهدأ الأحداث بمقدار wait
function debounce(fn, wait) {
  let t;
  return function (...args) {
    clearTimeout(t);
    t = setTimeout(() => fn.apply(this, args), wait);
  };
}

// Throttle: ينفّذ مرة واحدة كل limit كحد أقصى
function throttle(fn, limit) {
  let waiting = false;
  return function (...args) {
    if (waiting) return;
    fn.apply(this, args);
    waiting = true;
    setTimeout(() => { waiting = false; }, limit);
  };
}

// الاستخدام: صندوق بحث بيطلب النتائج بعد ما المستخدم يبطّل كتابة
const runSearch = debounce((q) => {
  fetch(`/api/search?q=${encodeURIComponent(q)}`)
    .then((r) => r.json())
    .then(renderResults);
}, 300);

input.addEventListener('input', (e) => runSearch(e.target.value));

السطر المهم في debounce هو clearTimeout(t): كل ضغطة بتلغي الطلب المؤجّل وتبدأ عدّ جديد. في throttle، القفل waiting هو اللي بيمنع التكرار قبل انتهاء الفترة.

سيناريو واقعي بالأرقام

مستخدم بيكتب كلمة "javascript" (10 حروف) في حوالي ثانية ونص. من غير debounce ده معناه 10 طلبات شبكة. مع debounce بمقدار 300ms، بيطلع طلب واحد بس بعد آخر حرف. لو عندك موقع بـ 50 ألف مستخدم في اليوم، وكل واحد بيعمل بحثين، تبقى العملية اتحوّلت من قرابة 1,000,000 طلب لـ 100,000 طلب يوميًا. توفير 90% في عدد الطلبات، وانخفاض مباشر في حمل قاعدة البيانات وتكلفة الـ API.

الـ trade-off بين الاتنين

Debounce بيكسبك أقل عدد طلبات ممكن، بس بيخسّرك زمن استجابة: المستخدم بيستنى 300ms بعد آخر حرف قبل ما يشوف نتيجة. Throttle بيكسبك تحديث مستمر وسلس (مثالي لمؤشر تقدّم أثناء الـ scroll)، بس بيسمح بعدد طلبات أكبر من debounce. الافتراض هنا إن الـ 300ms مقبولة لتجربة البحث؛ لو التطبيق بيحتاج استجابة فورية لكل نبضة، الاتنين مش الحل.

نقطة تانية: في نسخ "leading edge" (تنفّذ فورًا في أول حدث) و"trailing edge" (تنفّذ في آخر واحد). النسخة اللي فوق trailing. مكتبة زي Lodash بتديك التحكّم في الاتنين عبر خيارات leading وtrailing.

متى لا تستخدم أي منهم

لو الحدث نادر أصلًا زي ضغط زر submit مرة واحدة، مفيش داعي — بتضيف تعقيد بدون فايدة. لو محتاج فعلًا كل حدث بدقّة (تتبّع مسار الماوس في أداة رسم مثلًا) متستخدمش أي منهم لأنك هتفقد بيانات. ولطلبات البحث الحرجة، ضيف AbortController مع debounce علشان تلغي الطلب القديم بدل ما تستنى رده.

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

افتح أقرب input بحث عندك، لفّ الـ handler بتاعه في debounce بـ 300ms، وافتح تبويب Network في المتصفح. قيس عدد الطلبات قبل وبعد وإنت بتكتب نفس الكلمة. لو النزول مكانش قرب 90%، غالبًا الـ handler مش متلفوف صح.

المصادر

  • MDN Web Docs — setTimeout وaddEventListener.
  • Lodash Documentation — _.debounce و_.throttle (خيارات leading/trailing).
  • CSS-Tricks — Debouncing and Throttling Explained Through Examples بقلم David Corbacho.
  • MDN Web Docs — AbortController لإلغاء طلبات fetch.

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

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

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