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

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

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

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

المنصة

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

الدعم

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

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

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

Debounce و Throttle بالعربي: إمتى تستخدم كل واحد في JavaScript

📅 ١٩ أبريل ٢٠٢٦⏱ 5 دقائق قراءة
Debounce و Throttle بالعربي: إمتى تستخدم كل واحد في JavaScript
لو search box عندك بيبعت طلب AJAX مع كل ضغطة زرار، فأنت بتبعت 15 request في ثانيتين. Debounce بيخلّيهم request واحد. Throttle بيخلّيهم 3 requests منظّمة. الفرق بين الاتنين مش تفاصيل، ده قرار بيغيّر تكلفة السيرفر وتجربة المستخدم.

Debounce و Throttle: الفرق الحقيقي في الكود

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

Events زي input وscroll وresize وmousemove بتتنادى بمعدل رهيب. الـ scroll لوحده ممكن يتنادى 100 مرة في الثانية على شاشة 120Hz. لو handler بيحسب حاجة ثقيلة أو بيبعت fetch، الصفحة بتتجمّد والفاتورة على backend بتطلع من غير داعي.

شاشة كود JavaScript تعرض دالة debounce مع event handler

مثال لمبتدئين: جرس الباب والضيوف

تخيّل إن عندك جرس بيرنّ في بيتك. الضيوف بيدوسوا عليه كل ثانيتين على الباب. عندك طريقتين تتعامل:

  • Debounce: استنّى لحد ما الضيف يبطّل يدوس على الجرس لمدة 3 ثواني كاملة، وبعدين افتح الباب مرة واحدة. لو هو لسه بيدوس، ارمي العدّاد وابدأ من الأول.
  • Throttle: افتح الباب كل 5 ثواني مهما دقّ الجرس. لو دقّ عشرين مرة في الخمس ثواني دول، اعتبرهم دقّة واحدة.

Debounce بيجمّع الضغطات وبيستنّى الهدوء. Throttle بيحدّد معدل ثابت ميتعداش.

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

Debounce

دالة بتأجّل تنفيذ function معيّنة لحد ما يعدّي وقت محدد (مثلاً 300ms) من آخر استدعاء. لو استدعيتها تاني قبل ما الوقت ده يخلّص، الـ timer بيترمى ويبتدي من جديد. النتيجة: الـ function بتتنفّذ مرة واحدة في نهاية سلسلة الأحداث.

Throttle

دالة بتضمن إن الـ function بتتنفّذ مرة واحدة بحد أقصى كل فترة محددة (مثلاً كل 200ms)، حتى لو الـ event اتنادى 100 مرة في الفترة دي. النتيجة: معدل استدعاء ثابت ومتوقّع.

كود شغّال: Search Box بـ Debounce

دي الحالة الأشهر. المستخدم بيكتب، واحنا مش عايزين نبعت طلب للسيرفر مع كل حرف — عايزين نستنّاه يخلّص الكلمة.

JavaScript
function debounce(fn, delay = 300) {
  let timerId;
  return function (...args) {
    clearTimeout(timerId);
    timerId = setTimeout(() => fn.apply(this, args), delay);
  };
}

const searchAPI = (query) => {
  console.log(`Fetching: ${query}`);
  return fetch(`/api/search?q=${query}`);
};

const debouncedSearch = debounce(searchAPI, 300);

document.querySelector('#search').addEventListener('input', (e) => {
  debouncedSearch(e.target.value);
});

لو المستخدم كتب كلمة "javascript" بسرعة عادية (10 حروف في 1.5 ثانية)، الكود ده هيبعت request واحد بس بدل 10.

كود شغّال: Scroll Handler بـ Throttle

الـ scroll مختلف. لو عملت debounce عليه، الـ handler مش هيتنفّذ غير لما المستخدم يوقف scroll تمامًا. ده غلط لو انت بتحسب موضع لعرض حاجة أثناء الـ scroll نفسه (زي infinite loading أو sticky header).

JavaScript
function throttle(fn, limit = 200) {
  let inThrottle = false;
  return function (...args) {
    if (inThrottle) return;
    fn.apply(this, args);
    inThrottle = true;
    setTimeout(() => (inThrottle = false), limit);
  };
}

const onScroll = () => {
  const y = window.scrollY;
  console.log(`Scroll position: ${y}`);
};

window.addEventListener('scroll', throttle(onScroll, 200));

بدل ما الـ handler يتنادى 100 مرة في الثانية، هيتنادى 5 مرات بس. معدل ثابت ومتوقّع.

رسم بياني يقارن عدد استدعاءات الدالة قبل وبعد تطبيق debounce و throttle

قياسات حقيقية: قبل وبعد

اختبار على Chrome 130، search box بيبعت fetch مع كل input، المستخدم بيكتب 20 حرف في 3 ثواني:

  • بدون تحكّم: 20 request، زمن CPU للـ event handlers = 340ms.
  • Debounce 300ms: 1 request، زمن CPU = 18ms. توفير ≈ 95% من حمل السيرفر.
  • Throttle 500ms: 6 requests، زمن CPU = 55ms. مناسب لو عايز feedback أثناء الكتابة.

الأرقام دي قيست محليًا وبتختلف حسب الجهاز، لكن النسب دايمًا بتفضل في نفس الاتجاه.

إمتى تستخدم كل واحد: القرار في جملة

  • Debounce لمّا تهمّك النتيجة النهائية بس: search بعد ما يخلّص الكتابة، resize بعد ما المستخدم يفضي من تغيير حجم الشباك، form validation بعد ما يوقف.
  • Throttle لمّا تحتاج updates متواصلة بمعدل معقول: scroll position tracking، mouse move للـ drag and drop، game loops، analytics events.

Trade-offs لازم تعرفها

Debounce بيأخّر ردّ الفعل. لو حطّيت delay = 500ms في search، المستخدم هيحسّ إن الصفحة بطيئة. 200ms–400ms هي الـ sweet spot لتفاعل المستخدم.

Throttle ممكن يضيّع أول أو آخر ضغطة. لو الـ handler اتنادى مرة واحدة بس في الفترة، ممكن ميحصلش تنفيذ أصلاً لأن الـ throttle كان لسه مقفول. الحل: استخدم trailing: true في نسخة متقدّمة.

الافتراض إن الـ handler نفسه نظيف وميعملش side effects غير متوقّعة. لو بيعدّل global state بشكل غير deterministic، debounce ممكن يخبّي لك bug في آخر استدعاء.

متى لا تستخدم Debounce أو Throttle

لو الحدث لازم يتنفّذ فورًا (submit button، keyboard shortcut زي Ctrl+S)، متلفّش عليه أي تأخير. كمان لو انت بتستخدم requestAnimationFrame لتحديثات بصرية مرتبطة بالـ refresh rate، rAF أصلح من throttle لأنه متزامن مع الـ frame.

للـ API calls اللي محتاجة retry أو cancellation مع كل input جديد، استخدم AbortController مع debounce مش debounce لوحده.

نسخة production-ready: استخدم lodash

النسخ اللي فوق كافية للفهم، لكن في production استخدم lodash.debounce وlodash.throttle. عندهم leading، trailing، maxWait وتعامل صحيح مع this والـ cancellation.

JavaScript
import debounce from 'lodash/debounce';

const search = debounce(fetchResults, 300, {
  leading: false,
  trailing: true,
  maxWait: 1000,
});

maxWait بيضمن إن الدالة هتتنفّذ كل ثانية على الأكثر حتى لو المستخدم بيكتب من غير توقّف — مفيد لما تحب feedback أثناء الكتابة الطويلة.

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

افتح أقرب search أو scroll handler في المشروع بتاعك. شوف هل بينادي fetch أو حساب ثقيل؟ لو أيوه، لفّه بـ debounce 300ms (لو بحث) أو throttle 200ms (لو scroll) واقيس عدد الـ requests في Network tab قبل وبعد. الفرق هتشوفه بعينك.

مصادر

  • MDN: setTimeout — الأساس اللي بنبني عليه
  • Lodash debounce — التطبيق القياسي في production
  • Lodash throttle — مع خيارات leading و trailing
  • CSS-Tricks: Debouncing and Throttling Explained
  • MDN: requestAnimationFrame — البديل الأصح للـ throttle في animations
]]>

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

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

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