Debounce و Throttle: تحكّم في الأحداث المتكرّرة قبل ما تغرق السيرفر
هذا المقال يتطلب مستوى: متوسط. الافتراض إنك تكتب JavaScript مرتاح وتعرف addEventListener والـ closures، لكن لسه ما طبّقتش Debounce و Throttle بإيدك. لو انت مبتدئ، الأمثلة التوضيحية في كل قسم هتوصّلك الفكرة قبل الشرح التقني.
لو صندوق البحث في موقعك بيبعت طلب API مع كل حرف، فكلمة من 10 حروف بتولّد 10 طلبات، تسعة منهم نتيجتهم بتترمي فورًا. Debounce بيحوّلهم لطلب واحد، فبتوفّر حوالي 90% من حِمل البحث على السيرفر بسطرين كود.
المشكلة باختصار
فيه أحداث في المتصفح بتتطلق بمعدّل عالي: input مع كل ضغطة زر، scroll بيوصل من 30 لـ 60 مرة في الثانية، و resize و mousemove نفس الكلام. لو ربطت بكل حدث منهم عملية تقيلة — طلب شبكة، إعادة رسم، أو حساب layout — المتصفح هيتلكّع والسيرفر هياخد ضغط مالوش لزمة.
الطريقة الشائعة إن الناس بتسيب المعالج يشتغل مع كل حدث وتقول "هنحسّن بعدين". الطريقة دي بتفشل أول ما عدد المستخدمين يكبر. الحل مش إنك تشيل المعالج، الحل إنك تتحكّم في إيقاع تنفيذه. وده بالظبط شغل Debounce و Throttle.
Debounce: استنّى لما النشاط يهدأ
المثال البسيط الأول
تخيّل باب المصعد الأوتوماتيكي. كل ما حد جديد يقف في الباب، العدّاد بيرجع من الأول والباب بيفضل مفتوح. الباب ما بيقفلش مع كل شخص، بيقفل مرة واحدة بس بعد ما يعدّي وقت كامل من غير ما حد يقف. يعني هو بيستنّى "الهدوء" قبل ما يتحرّك.
Debounce بيشتغل بنفس المنطق. كل نداء جديد بيلغي العدّاد القديم ويبدأ واحد جديد. الدالة الحقيقية ما بتتنفّذش إلا لما يهدأ تدفّق الأحداث تمامًا لمدة الانتظار اللي انت حدّدتها.
التعريف العلمي
Debounce هو higher-order function بياخد دالة وفترة انتظار، ويرجّع نسخة مغلّفة منها. كل استدعاء للنسخة المغلّفة بيمسح أي setTimeout سابق ويجدوِل واحد جديد. الدالة الأصلية بتتنفّذ مرة واحدة فقط، بعد آخر استدعاء بفترة الانتظار كاملة.
function debounce(fn, delay) {
let timerId;
return function (...args) {
clearTimeout(timerId);
timerId = setTimeout(() => fn.apply(this, args), delay);
};
}Throttle: إيقاع ثابت مهما زاد الضغط
المثال البسيط الأول
تخيّل أتوبيس بيتحرّك من المحطة كل 10 دقايق بالظبط. مش فارق وقف 5 ركاب ولا 50، الأتوبيس بيمشي على نفس الإيقاع، واللي جه في وقت بينّي بيستنّى الرحلة الجاية. مفيش انتظار "للهدوء" زي المصعد، فيه إيقاع ثابت.
Throttle بيعمل كده مع الأحداث: بيسمح بتنفيذ واحد كل فترة، وأي حدث بيقع جوّه الفترة دي بيتجاهله.