Reputation: 1121
I am working on task in which each time a user scrolls or resizes the screen I would like to recalculate a css properties for an element.
Let's say I want to impl. a progress bar and the progress is reported based on the scroll position in the window
<div class='progress-bar-wrap'>
<div class='progress-bar-progress'></div>
</div>
function updateScrollProgress () {
this.progressIndicator.css('width', this.calculateProgressBarWidth() + 'px');
}
I tried to hook on scroll and resize events, but this seem to have a laggy effect.
window.on('scroll', updateScrollProgress)
window.on('resize', updateScrollProgress)
I tried in the scroll and resize event handlers to requestAnimationFrame
window.on('scroll', function(){window.requestAnimationFrame( updateScrollProgress))
window.on('resize', function(){window.requestAnimationFrame( updateScrollProgress))
And experienced huge improvement in most browsers, however it is yet occasionally laggy.
I tried to request another frame, when from the requestAnimationFrame handler:
function updateScrollProgress () {
window.requestAnimationFrame( updateScrollProgress)
this.progressIndicator.css('width', this.calculateProgressBarWidth() + 'px');
}
This completely eliminated the laggy effect, but comes to the cost of endless loop of calls to this method, even when no recalculations are needed.
Is there a way to hook a handler just before the browser decides to draw element(s), so that I can provide/set the those "dynamic" css values for a property?
Upvotes: 0
Views: 70
Reputation: 1074148
What's what you're doing when you use requestAnimationFrame
. If you've gotten rid of the lag using it, it's unclear why you say the function is running "too often." Usually in this sort of context, "too often" means "is causing lag" (by running too often and slowing things down). If yours isn't, then...?
If you want the handler called less often, you can debounce it, but then you'll probably notice delays before the changes you want (because you've debounced), which it sounds like is what you're trying to avoid.
In any case, requestAnimationFrame
is, for now at least, the right tool for the "just before the browser renders the frame" job.
Upvotes: 1
Reputation: 1786
Wrap your event function through a debounce function:
More info on debounce functions here:
https://davidwalsh.name/javascript-debounce-function
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
var myEfficientFn = debounce(function() {
// All the taxing stuff you do
}, 250);
window.addEventListener('resize', myEfficientFn);
Upvotes: 0