1

I need to adjust image sizes in a lazy loading mechanism. The final image paths are stored in attribute data-src, if lazy loading is enabled. For optical reasons, I don't want to wait until lazy loading is done, so I've tried the following:

  window.addEventListener('load', function() {
    const aImages = document.getElementsByClassName('article-image');
    for ( var i=0;i<aImages.length;i++ ) {
      const wrp = aImages[i].parentElement;
      var imgHeight, imgWidth;
      // if lazyload
      if ( aImages[i].getAttribute('data-src') ) {
        var img = new Image();
        img.onload = function() { imgHeight = this.naturalHeight; imgWidth = this.naturalWidth };
        img.src = aImages[i].getAttribute('data-src');
      } else {
        imgHeight = aImages[i].naturalHeight;
        imgWidth = aImages[i].naturalWidth;
      }
      var dim = calcAspectRatioFit(imgWidth, imgHeight, wrp.clientWidth, wrp.clientHeight);
      console.log('['+i+']\n' + 'dim.width:  '+dim.width + '\ndim.height: '+dim.height + '\ntypeof(wrp): '+typeof(wrp) + '\nwrp.clientWidth:  '+wrp.clientWidth + '\nwrp.clientHeight: '+wrp.clientHeight + '\nimgWidth:  '+imgWidth + '\nimgHeight: '+imgHeight);
      aImages[i].style.setProperty('width', dim.width + 'px', 'important');
      aImages[i].style.setProperty('height', dim.height + 'px', 'imoprtant');
    }
  });

Guess the problem is the onload-function. If I set a breakpoint between it and before calcAspectRatioFit(), everything works as excepted. Guess 'img' then has enough time to load.

Debug-Output from console.log():

  [0]
  dim.width:  NaN
  dim.height: NaN
  typeof(wrp): object
  wrp.clientWidth:  222
  wrp.clientHeight: 192
  imgWidth:  undefined
  imgHeight: undefined

Any ideas how to solve this?

// Edit 2:

Of course, the problem was, that the last four lines didn't wait for img.onload() to be executed. Thanks @Peter Krebs for this hint. Here is a QnD solution which works fine. (Added anonymous wrapper fnc to copy i)

window.addEventListener('load', function() {
  const aImages = document.getElementsByClassName('article-image');
  const exec = function(i) {
    const wrp = aImages[i].parentElement;
    var dim = calcAspectRatioFit(aImages[i].naturalWidth, aImages[i].naturalHeight, wrp.clientWidth, wrp.clientHeight);
    aImages[i].style.setProperty('width', dim.width + 'px');
    aImages[i].style.setProperty('height', dim.height + 'px');
  }
  for ( var i=0;i<aImages.length;i++ ) {
    if ( aImages[i].getAttribute('data-src') ) {
      aImages[i].onload = (function(i) { return function() { exec(i) } })(i);
      this.src = aImages[i].getAttribute('data-src');
    } else { exec(i) }
  }
});
stuck1a
  • 13
  • 6
  • 1
    `img.onload` is a function which will be executed later when the image is loaded. Only then can the dimensions be read from the image. So during the last four lines you try to work with variables which haven't been set yet. – Peter Krebs Sep 28 '22 at 11:53
  • I see, `img.onload` will not be executed. But how can I force the image to load? Without the onload-wrap, the results are the same (see Edit). I followed this hint: [link](https://stackoverflow.com/a/2342181/16822054) – stuck1a Sep 28 '22 at 12:00
  • Or more precisely, `img.onload` will be executed later when the image has finished loading. You can't make the image load faster than it does. But you can move your last four lines into a function and call it at the end of the `else` and within the `onload` function. – Peter Krebs Sep 28 '22 at 12:22
  • 1
    Oh, guess I've missunderstood you first. Now I got it. Thanks for your advise. I've added a quick and dirty solution which works as Edit 2 – stuck1a Sep 28 '22 at 12:26
  • Okay great you got it working yourself You can write an answer to your own question with the solution if you want, that's not uncommon here. – Peter Krebs Sep 28 '22 at 13:35

0 Answers0