0

So I have this page where on a button click, an image is added embellishments after performing various calculations on its meta-data which is stored as data-attributes.

Since the calculations can take a few seconds, I want to show an overlay on the image. So I do:

$(selectedImageId).addClass('loading');
//perform series of calculations here...
$(selectedImageId).removeClass('loading').addClass('calculated-embellishments');

I would imagine the script to first show the loading overlay on the image, then perform the lengthy calculations, then replace the overlay with the selected embellishment class. However it seems like the DOM is updated only at the end such that I never see the loading class, it just directly jumps from the plain image to the embellishment class after a few seconds.

If I add an alert('test') just before the last line which adds the embellishment then I can see the loading overlay on the image, but not otherwise.

How can I make this work the way I want it to, as I explained above? Any pointers are very welcome!

Undefined Variable
  • 4,196
  • 10
  • 40
  • 69
  • 1
    Add more code, or use jsfiddle, this piece of code is formally correct... – Baro Jan 07 '16 at 18:03
  • The `perform series of calculations here... ` part is over 75 lines that includes multiple subroutines. I dont really think that I can fiddle it, nor that it would help you much. I am hoping someone can give me a pointer perhaps from experience on what might be stalling the preloader – Undefined Variable Jan 07 '16 at 18:10
  • you could listen for the load event on the image you want to replace to, when each image triggers the load event then swap your placeholder image. – Amr Morsy Jan 07 '16 at 18:16
  • I understand, however, so it's hard to help you. However, try to change "addClass" with an immediately recognizable style as ".css ('border', 'solid 5px #FF0000')" only for test. – Baro Jan 07 '16 at 18:16

2 Answers2

0

You probably want to execute your calculations using setTimeout.

var WAIT = 10; // experiment with small values here

$(selectedImageId).addClass('loading');

setTimeout(function () {
  //perform series of calculations here...
  $(selectedImageId).removeClass('loading').addClass('calculated-embellishments');
}, WAIT);

If you want to play around with the timeout length, here is a jsfiddle with a demo using a similar situation: https://jsfiddle.net/v2n19w4d/1/ I find that a timeout length close to zero was not working.

This is really an issue with getting the DOM to update before it is blocked while doing your calculations. See jQuery append in loop - DOM does not update until the end, for example.

Community
  • 1
  • 1
csum
  • 1,782
  • 13
  • 15
0

What probably happens is that your "lengthy calculations" make the browser "hang" for processing, not having a chance to re-paint your image to reflect the newly added loading class.

Then once the calculations are done, your last instruction replaces the loading class by calculated-embellishments class, and now the browser has time to re-paint. But the loading class is already gone.

You have at least 3 workarounds to let the browser actually display your loading class before your calculations keep it busy:

  • Use a setTimeout as proposed by @csum, which is a bet on how much time the browser would need before doing the re-paint that will show your image with loading class. Hence the need to "test" different timeout values, but still without any guarantee as the result will depend on each client current performance (CPU, memory, current CPU load!).
  • Start your calculations in a callback of the "load" event of your overlay (if it is an image). But I am not sure if "load" event is a guarantee of the image (overlay) being painted (shown on screen).
  • Use 2 nested requestAnimationFrame to make sure at least 1 re-paint has occured, before you start your calculations.
ghybs
  • 47,565
  • 6
  • 74
  • 99