For example, let's say we have two versions of lazyload (see code below). In terms of performance, is versionII better than version I?
const imgs = document.querySelectorAll('img');
window.addEventListener('scroll' , lazyload);
// version I
function lazyload() {
imgs.forEach((img) => {
if (img.offsetTop < window.innerHeight + window.pageYOffset) {
img.src = img.dataset.src;
}
}
}
// version II
function lazyload() {
const innerHeight = window.innerHeight;
const pageYOffset = window.pageYOffset;
imgs.forEach((img) => {
if (img.offsetTop < innerHeight + pageYOffset) {
img.src = img.dataset.src;
}
}
I'll rephrase your specific question like this:
Is it costly to access
window.innerHeight
and/orwindow.pageYOffset
?
It can be. According to Paul Irish of the Google Chrome Developer Tooling team:
All of the below properties or methods, when requested/called in JavaScript, will trigger the browser to synchronously calculate the style and layout*. This is also called reflow or layout thrashing, and is common performance bottleneck.
...
window
window window.scrollX, window.scrollY window.innerHeight, window.innerWidth window.getMatchedCSSRules() only forces style
-- What forces layout / reflow (emphasis mine)
At the bottom of that document, Paul indicates the layout reflow will only occur under certain circumstances. The portions below (with my added emphasis) answer your question better and more authoritatively than I could.
- Reflow only has a cost if the document has changed and invalidated the style or layout. Typically, this is because the DOM was changed (classes modified, nodes added/removed, even adding a psuedo-class like :focus).
- If layout is forced, style must be recalculated first. So forced layout triggers both operations. Their costs are very dependent on the content/situation, but typically both operations are similar in cost.
- What should you do about all this? Well, the More on forced layout section below covers everything in more detail, but the
short version is:
for
loops that force layout & change the DOM are the worst, avoid them.- Use DevTools Timeline to see where this happens. You may be surprised to see how often your app code and library code hits this.
- Batch your writes & reads to the DOM (via FastDOM or a virtual DOM implementation). Read your metrics at the begininng of the frame (very very start of rAF, scroll handler, etc), when the numbers are still identical to the last time layout was done.
Changing the src
attribute is probably sufficient to "invalidate the style or layout." (Although I suspect using something like correctly-dimensioned SVG placeholders for lazy-loaded images would mitigate or eliminate the cost of the reflows.)
In short, your "version I" implementation is preferable and has, as far as I can tell, no real disadvantages.
As shown above, reading properties from the window object can be expensive. But others are right to point out a couple things: