JavaScript: Detecting the end of native smooth scrolling

When you use native smooth scrolling Show archive.org snapshot there is no built-in method to detect the end of the scrolling animation. Methods like scrollTo() Show archive.org snapshot don't return a promise. We will eventually get a scrollend Show archive.org snapshot event, but that is still some time away Show archive.org snapshot .

Until then I'm using the following awaitScrollEnd() function as a workaround. It returns a promise that resolves when the given Document or Element does not receive a scroll event for 75 milliseconds:

import debounce from 'lodash-es/debounce'

function awaitScrollEnd(viewport, delay = 75) {
  return new Promise((resolve) => {
    function done() {
      viewport.removeEventListener('scroll', debouncedDone)
      resolve()
    }

    // We consider scrolling to have stopped after we haven't received
    // a `scroll` event for `delay` milliseconds.
    //
    // The default delay (75) assumes a minimum framerate of ~13 FPS
    // while scrolling.
    let debouncedDone = debounce(done, delay)
    viewport.addEventListener('scroll', debouncedDone, { passive: true })
    debouncedDone()
  })
}

Use it after you started a native scrolling motion:

element.scrollIntoView({ behavior: 'smooth' })
await awaitScrollEnd(document)

Note that import 'lodash-es/debounce' only imports the debounce function (and possibly few dependencies) into your JavaScript bundle, not the entire Lodash library.
While you could implement debouncing yourself (using timeouts), Lodash already comes with tests. There is no real reason to implement it yourself.

Henning Koch 12 months ago