Event when user stops scrolling

Here is another more generic solution based on the same ideas mentioned:

var delayedExec = function(after, fn) {
    var timer;
    return function() {
        timer && clearTimeout(timer);
        timer = setTimeout(fn, after);
    };
};

var scrollStopper = delayedExec(500, function() {
    console.log('stopped it');
});

document.getElementById('box').addEventListener('scroll', scrollStopper);

You can make the scroll() have a time-out that gets overwritten each times the user scrolls. That way, when he stops after a certain amount of milliseconds your script is run, but if he scrolls in the meantime the counter will start over again and the script will wait until he is done scrolling again.

Update:

Because this question got some action again I figured I might as well update it with a jQuery extension that adds a scrollEnd event

// extension:
$.fn.scrollEnd = function(callback, timeout) {          
  $(this).on('scroll', function(){
    var $this = $(this);
    if ($this.data('scrollTimeout')) {
      clearTimeout($this.data('scrollTimeout'));
    }
    $this.data('scrollTimeout', setTimeout(callback,timeout));
  });
};

// how to call it (with a 1000ms timeout):
$(window).scrollEnd(function(){
    alert('stopped scrolling');
}, 1000);
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>

<div style="height: 200vh">
  Long div
</div>

Here is a simple example using setTimeout to fire a function when the user stops scrolling:

(function() {        
    var timer;
    $(window).bind('scroll',function () {
        clearTimeout(timer);
        timer = setTimeout( refresh , 150 );
    });
    var refresh = function () { 
        // do stuff
        console.log('Stopped Scrolling'); 
    };
})();

The timer is cleared while the scroll event is firing. Once scrolling stops, the refresh function is fired.

Or as a plugin:

$.fn.afterwards = function (event, callback, timeout) {
    var self = $(this), delay = timeout || 16;

    self.each(function () { 
        var $t = $(this);
        $t.on(event, function(){
            if ($t.data(event+'-timeout')) {
                clearTimeout($t.data(event+'-timeout'));
            }
            $t.data(event + '-timeout', setTimeout(function () { callback.apply($t); },delay));
        })
    });
    return this;
};

To fire callback after 100ms of the last scroll event on a div (with namespace):

$('div.mydiv').afterwards('scroll.mynamespace', function(e) {
        // do stuff when stops scrolling
        $(this).addClass('stopped');
    }, 100
);

I use this for scroll and resize.