לדלג לתוכן

מה זה Debouncing ו-Throttling בפרונטאנד

תארו לעצמכם שדה חיפוש שמריץ בקשת רשת לשרת בכל הקשה על מקש. משתמש שמקליד מילה בת שמונה אותיות גורם לשמונה בקשות רשת, רוב הזמן מיותרות לגמרי כי המשתמש עוד לא סיים להקליד. זו בדיוק הבעיה ש-Debouncing ו-Throttling נועדו לפתור, ולמרות שהם נשמעים דומים, הם פותרים אותה בדרכים שונות לגמרי.

הבעיה - אירועים שיורים מהר מדי

יש בדפדפן אירועים (events) שיכולים להתרחש עשרות או מאות פעמים בשנייה: הקלדה, גלילה, שינוי גודל חלון, תזוזת עכבר. אם מחברים לאירוע כזה פונקציה כבדה - קריאת רשת, חישוב מורכב, עדכון ממשק כבד - הדפדפן פשוט לא מספיק לעמוד בקצב, וזה גורם לתחושת גמגום (jank) ולפעמים גם לעומס מיותר על השרת.

Debounce - לחכות עד שהאירועים נרגעים

Debounce אומר: תריץ את הפונקציה רק אחרי שעברה תקופה מסוימת בלי שהאירוע קרה שוב. כל פעם שהאירוע מתרחש, הטיימר מתאפס מחדש. זה מתאים בול לדוגמה של שדה חיפוש - רוצים להריץ את החיפוש רק אחרי שהמשתמש הפסיק להקליד, לא בכל אות בנפרד.

function debounce(fn, delay) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

const search = debounce((query) => {
  fetchResults(query);
}, 300);

input.addEventListener("input", (e) => search(e.target.value));

עם הקוד הזה, אם המשתמש מקליד ברצף, הבקשה לשרת נשלחת רק 300 מילישניות אחרי ההקשה האחרונה, לא אחרי כל הקשה בנפרד.

Throttle - להגביל את הקצב, לא לחכות שהוא ייגמר

Throttle אומר משהו קצת שונה: תריץ את הפונקציה לכל היותר פעם בכל פרק זמן קבוע, גם אם האירוע ממשיך לקרות ברצף. בניגוד ל-debounce, הפונקציה כן רצה תוך כדי שהאירוע ממשיך, פשוט בקצב מוגבל.

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

window.addEventListener(
  "scroll",
  throttle(() => {
    updateScrollIndicator();
  }, 200)
);

זה מתאים לאירועים כמו גלילה או תזוזת עכבר, שבהם רוצים לקבל עדכונים לאורך כל הפעולה, פשוט לא בכל פריים בנפרד.

איך זוכרים את ההבדל

דרך פשוטה לזכור: debounce מחכה לשקט, throttle קובע קצב. אם הפעולה שלכם רלוונטית רק אחרי שהמשתמש סיים לגמרי (חיפוש, שמירה אוטומטית של טופס), debounce מתאים. אם הפעולה שלכם צריכה להגיב לאורך כל הפעולה (גלילה, resize, גרירה), throttle מתאים יותר.

שימוש בפועל בלי לכתוב הכל מאפס

בפרויקט אמיתי לא חייבים לכתוב את הפונקציות האלה בעצמכם בכל פעם. ספריות כמו lodash מציעות מימוש בדוק ומהיר, וגם פריימוורקים מודרניים לפעמים מציעים hook מוכן לתבנית הזו. אבל שווה להבין את המנגנון הפנימי, כי זה עוזר לדבג בעיות ביצועים כשמשהו לא עובד כמו שציפיתם.

מאיפה ממשיכים ללמוד

הבנת debounce ו-throttle היא חלק מהבנה רחבה יותר של JavaScript אסינכרוני ואירועי דפדפן. אם אתם בונים את הבסיס הזה, יש לנו קורס צד לקוח בחינם שמלמד את היסודות האלה בצורה מסודרת.

לסיכום

Debounce ו-throttle הם שני כלים פשוטים שפותרים בעיה אמיתית מאוד - אירועים שיורים מהר מדי בשביל הקוד שלכם להתמודד איתם. debounce מתאים כשרוצים לחכות לשקט, throttle כשרוצים לשמור על קצב קבוע לאורך זמן. שני הכלים האלה קטנים, אבל ההבדל שהם עושים לביצועים גדול בהרבה ממה שנראה במבט ראשון.

יש לכם אירוע בדפדפן שיורה יותר מדי פעמים? שאלו בקהילה ונעזור לבחור את הפתרון הנכון.

הצטרפו לקהילה בדיסקורד