0

I want my function to fire on scroll, but then wait 250ms until it may fire again.

function myFunction() {
    console.log('hello');
}

$(window).on('scroll', function() {
        myFunction();
});

I have tried a timeout:

$(window).on('scroll', function() {
    setTimeout(function() {
        myFunction();
    }, 250);
});

However this method delays for 250ms before firing the function.

flinch85
  • 340
  • 2
  • 16
  • This is `throttle` you can also `debounce`, which will fire the event after timeout only if it's not been raised within the timeout (ie each event resets the timeout then it only gets "fully" fired if none have been raised during the timeout) – freedomn-m May 12 '22 at 16:50
  • With throttle, you get an event then don't get any more within the timeout. In your case, you'd get the first scroll, then lose the remaining. Depends on what `myFunction()` does - if it looks at the scroll position, then you'll want to debounce to ensure you get the last/final event not the first. – freedomn-m May 12 '22 at 16:54
  • There's various answers already on SO, eg: https://stackoverflow.com/questions/9424752/jquery-change-with-delay it's unclear exactly which would suit you – freedomn-m May 12 '22 at 16:57
  • 1
    Based on [this answer] you can clear the "doing" variable in the timeout. https://jsfiddle.net/Lazf4jkc/ this will give you the first event immediately then no other events for 250ms - with this method you will not get the last event. – freedomn-m May 12 '22 at 17:08
  • 1
    @freedomn-m, the jsfiddle is exactly what I was looking for thank you. – flinch85 May 12 '22 at 17:18
  • Just noted I missed the link to the original - I'll add an answer as it's not exactly the same, just based on. – freedomn-m May 12 '22 at 17:39

2 Answers2

1

Based on this answer, you can add a flag so that additional events are not fired, then clear that flag using a timeout.

Note that this will lose/drop events within the timeout, so should not be used for something like user keyboard input; where debounce would be more suitable.

var active = false;

$(window).on('scroll', function() {
    if (active) return;
    active = true;
    
    myFunction();
    setTimeout(function() {
        active = false;
    }, 250);
});

function myFunction() { console.log("scroll"); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style='height:30000px;'>
something to scroll
</div>

This is a basic throttle implementation. Improvements would be to make it modular / namespace'd and/or store the "active" flag on the element itself; so that it the same event can be reused for multiple elements and doesn't create lots of global variables.

freedomn-m
  • 27,664
  • 8
  • 35
  • 57
0

Simply call your function once outside of setTimeout.

$(window).on('scroll', function() {
    myFunction(); // call once

    setTimeout(function() {
        myFunction();
    }, 250); // repeat call after 250ms
});

Use setInterval instead of setTimeout if you want repeated calls every 250ms.

SNag
  • 17,681
  • 10
  • 54
  • 69