debounce doesn't work with js scrollIntoView when behaviour:smooth

lodash's debounce function doesn't work properly when listening to scroll event that's caused by js native element.scrollIntoView

HTML

<nav>
<button id="btn1" onclick="goTo(1)">1</button>
<button id="btn2" onclick="goTo(2)">2</button>
</nav>
<div id="el1">1</div>
<div id="el2">2</div>

JS

function goTo(x) {
 const elm = document.getElementById(`el${x}`);
  elm.scrollIntoView({
    behavior: "smooth",
    block: "start"
  });
  let func = _.debounce(() => {
    document.documentElement.scrollBy({
      top: -20,
      behavior: "smooth"
  })
}, 500)
  document.addEventListener('scroll', e => {
    func()
  })
}

Issue reproduction: https://jsfiddle.net/do6bqfx7/4/

1 answer

  • answered 2018-01-11 21:21 raina77ow

    It's not about debounce. See, scrollBy invoked in func is also a scroll - that's why it's handled by delayed call of func again, and again, and again. What you actually need is to make func an (effectively) single-time event handler. One possible approach (demo):

    function goTo(x) {
      const elm = document.getElementById(`el${x}`);
      elm.scrollIntoView({
        behavior: "smooth",
        block: "start"
      });
      let func = _.debounce(() => {
        document.removeEventListener('scroll', func);
        document.documentElement.scrollBy({
          top: -20,
          behavior: "smooth"
        });
      }, 500);
      document.addEventListener('scroll', func);
    }