Throttling vs Debouncing

by Hajime Yamasaki Vukelic

HTML

<div id="area" class="area">
  <span class="label">real-time coords:</span>
  <span id="rx">(initial)</span>,
  <span id="ry">(initial)</span>
  <br>
  <span class="label">throttled coords:</span>
  <span id="tx">(initial)</span>,
  <span id="ty">(initial)</span>
  <br>
  <span class="label">debounced coords:</span>
  <span id="dx">(initial)</span>,
  <span id="dy">(initial)</span>
</div>

CSS

body,
html,
.area {
  width: 100%;
  height: 100%;
}

.label {
  display: inline-block;
  width: 8rem;
}

Babel + JSX

const area = document.getElementById("area");

const state = {
  throttled: {
    x: 0,
    y: 0,
  },
  debounced: {
    x: 0,
    y: 0,
  }
}

area.addEventListener("mousemove", coordUpdater("r"));
area.addEventListener("mousemove", throttled(200, coordUpdater("t")));
area.addEventListener("mousemove", debounced(200, coordUpdater("d")));

function handler(e) {
  mouseToState(e);
  updateDisp(e);
}

function coordUpdater(prefix) {
  const x = document.getElementById(`${prefix}x`);
  const y = document.getElementById(`${prefix}y`);
  return function (e) {
    x.innerText = e.clientX;
    y.innerText = e.clientY;
  }
}  

function throttled(delay, fn) {
  let lastCall = 0;
  return function (...args) {
    const now = (new Date).getTime();
    if (now - lastCall < delay) {
      return;
    }
    lastCall = now;
    return fn(...args);
  }
}

function debounced(delay, fn) {
  let timerId;
  return function (...args) {
    if (timerId) {
      clearTimeout(timerId);
    }
    timerId = setTimeout(() => {
      fn(...args);
      timerId = null;
    }, delay);
  }
}