0

I have a one-page mobile site that I'm working on that brings up a loading widget that comes up between page navigation. On old android phones (I'm testing on a Galaxy S), painting the loading icon is deferred until much of the other processing is done. This of course largely defeats the purpose of the loading icon.

$("button").click(function() {
    $(".cover").show();
    $(window).scrollTop(0);
    for(var i = 0; i < 1000; i++) {
      console.log($(".body").css("width"));
    }
    setTimeout(function() {
        $(".body").toggleClass("toggle");
        $(".cover").hide();
    }, 1000);
});

This sample code accurately demonstrates what is functionally happening on my site. There is a command to display the loading widget, then some relatively heavy processing (of course on the actual page, it's a variety of different things, but both this demo and my page behave the same way). When you press the button on the Galaxy S, there is a bunch of processing, then loading widget appears for the one second timeout.

Why doesn't it show the loading widget display first and how can I force it to?

Here is a jsbin with the demo so you can see it on a phone: JSBin

Will Reese
  • 2,801
  • 2
  • 15
  • 27

1 Answers1

1

If you let the event loop finish, the browser will draw. You can do that like this:

$("button").click(function() {
    $(".cover").show();
    $(window).scrollTop(0);
    setTimeout(function() {
        for(var i = 0; i < 1000; i++) {
          console.log($(".body").css("width"));
        }
        setTimeout(function() {
            $(".body").toggleClass("toggle");
            $(".cover").hide();
        }, 1000);
    }, 1);
});

There are other ways to force specific browsers to repaint, but you'd have to test which ones work in your specific cases. Here are some other references about those other methods:

Force DOM redraw/refresh on Chrome/Mac

How can I force WebKit to redraw/repaint to propagate style changes?

Force repaint of element with javascript

Force redraw on an element with jQuery


As to why this is not the same in every browser, that's because there are no universal standards for when a browser will repaint pending changes other than when the browser gets back to the event loop. So, it is up to a given browser implementation if it will paint while Javascript is still running (before the current JS thread of execution finishes) or whether it will wait until the JS is done. The work-arounds above all exploit observed behaviors to create work-arounds rather than trigger documented, standards-defined behaviors.

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Ah, this seems like it should work and does for the example. But for some reason it won't work on my actual site. It scrolls to the top first (the second command), then waits for a chunk of the request to resolve before throwing up the loading widget. – Will Reese May 08 '15 at 06:27
  • @WillReese - I wonder if there's a delay before the image itself is done being loaded and available to be displayed and that timing might vary by platform, browser or network? I could only help more specifically, if you shared the actual link to your site and a description of the specific case where it isn't working as desired. – jfriend00 May 08 '15 at 06:32
  • Ok, i finally got it to work. In my actual site, the real problem has to do with the scrolling... the page scrolls to the top before the overlay appears. Unlike what you actually suggested, I threw the scrollTop command into the setTimeout, not thinking it was relevant. Once I moved it back into the functions main scope, it works correctly. Can you explain what's happening with the execution order here? – Will Reese May 08 '15 at 06:40
  • @WillReese - I'd have to diagnose the actual page to know for sure, but I put the scroll operation before the `setTimeout()` so it would get painted too right away. – jfriend00 May 08 '15 at 06:53
  • That's what I would expect to happen, but what confuses me is why putting the scroll inside the `setTimeout()` results in the page scrolling first, then showing the overlay, whereas putting it outside causes it to resolve as desired – Will Reese May 08 '15 at 08:03