5

In my html page there are external images and flashes, sometime they load slowly. My gwt app always starts running after they are loaded. I use xsiframe linker.

Is there any way to start running gwt before loading any images and resources which are inside body? Or make sure loading other things will not block starting gwt.

EDIT: I have created a minimal project that reproduces the problem:

entry point:

public class MyEntryPoint implements EntryPoint {
    public void onModuleLoad() {
        Window.confirm("onModuleLoad");
    }
}

html page:

<html><head>
    <script type="text/javascript"src="nocache.js"></script>
</head><body>
    <!-- http://stackoverflow.com/questions/100841/artificially-create-a-connection-timeout-error -->
    <img src="http://10.255.255.1/timeout.gif" alt="timeout image" />
</body></html>
Cœur
  • 37,241
  • 25
  • 195
  • 267
Ali Shakiba
  • 20,549
  • 18
  • 61
  • 88
  • The loading order and which elements are blocking to GWT's execution is explained here https://developers.google.com/web-toolkit/doc/latest/DevGuideOrganizingProjects#DevGuideBootstrap. Which might help you. – jaxb May 17 '12 at 10:17
  • @jaxb Thank you, I have read that. Sadly it has not answered my specific question (confusion). – Ali Shakiba May 17 '12 at 10:38
  • Did you try putting the *.nocache.js inside the first script tag in the body? – Ganesh Kumar May 17 '12 at 14:21
  • @GaneshKumar Yes, I have tried that. nocache.js always starts and loads browser specific script, but calling onModuleLoad is blocked until images are loaded. – Ali Shakiba May 17 '12 at 14:29
  • As per the GWT documentation, onModuleLoad() call need not wait till completion of loading of images. Can you post your html page? – Ganesh Kumar May 17 '12 at 16:20
  • @GaneshKumar I have added sources. – Ali Shakiba May 18 '12 at 04:41
  • would it be a viable option to add the images and flash files via gwt code? this way, onModuleLoad() already has been called when the browser starts downloading the files. – MarioP May 18 '12 at 10:57
  • The reason why onModuleLoad() is called after the image load is that *.cache.html, file that contains actual javascript, is loaded asynchronously. So loading of *.cache.html will happen in parallel with one or more resource files depending on number of asynchronous connections. The loading of this cache.html file may be taking more time than the image loading.Use the network profiler available in Chrome to determine load time for different resources. – Ganesh Kumar May 18 '12 at 13:55
  • @GaneshKumar I have already monitored network connections (in both firefox and chrome) there is no problem with loading gwt files. Gwt files are cached and loaded them from a cdn. Have you tried my code? – Ali Shakiba May 18 '12 at 15:30
  • @MarioP In my app html+css pages need to be viewable without gwt (ajax). Gwt is used to add server interaction functionality to pages. – Ali Shakiba May 18 '12 at 15:39
  • Yes, I have tried your code. What I observed is, in chrome, onModuleLoad() was called after the image load. But, the subsequent refresh of the browser resulted in onModuleLoad() being called before the image load. But in IE image was always loaded before the onModuleLoad(). – Ganesh Kumar May 18 '12 at 15:41
  • @GaneshKumar I guess this is a gwt bug. – Ali Shakiba May 18 '12 at 15:44
  • another question, is there a specific reason for using the xsiframe linker? it seems the problem only occurs using this linker (tested in firefox/chrome) – MarioP May 18 '12 at 15:44
  • @GaneshKumar Any way thanks for your effort. – Ali Shakiba May 18 '12 at 15:45
  • @MarioP I serve gwt files from a different domain (a cdn). – Ali Shakiba May 18 '12 at 16:17
  • seems like this is how browsers work :-/ you could make two versions of the site, one with gwt (creating the HTML in onModuleLoad) and a noscript-tag with a redirect to the second version without gwt. – MarioP May 22 '12 at 11:32
  • @MarioP I guess the problem is with gwt and when it decides to start executing. I don't think the same problem exists with other js frameworks. Any way thanks for you help. – Ali Shakiba May 22 '12 at 12:45

4 Answers4

1

First, sorry for "answering" when I don't know too much about GWT, and for presenting a pretty ugly hack.

Now then, two asynchronous loads with undefined outcome sounds like a race condition to me. So I'd say you need to "lock" your images/flash until the app loads and "unlocks" them.

One way to do this might be to give all the assets a dummy attribute instead of src, and then to have the app copy the dummy over to the real src. It would look something like this:

HTML example:

<img data-src="site.com/image.jpg" alt="loading..." />

Entry point:

public class MyEntryPoint implements EntryPoint {
    public void onModuleLoad() {
        var images = document.getElementsByTagName('img');
        for(var i=0; i<images.length; ++i){
            var dataSrc = images[i].getAttribute('data-src');
            if(dataSrc) images[i].src = dataSrc;
        }
        // ... rest of your entry point code
    }
}

Maybe you can adapt something like this to fit your needs.

pieman72
  • 836
  • 8
  • 14
  • Thanks, the problem is not with connections, I have described it in comments. I have also described why your workaround doesn't work for me, I need a viewable website even without ajax/js/gwt. If I had that option I would load page contents asynchronously. In fact I'm trying to figure out what the problem is with gwt. – Ali Shakiba May 22 '12 at 12:44
  • Sorry. You're right, I had overlooked the requirement that the page be visible without the app. I still say you have a race condition, though, and you will need to "lock" the images. Can you use an inline script in the page itself to unlock the images after a timeout? That way you don't rely on the app, but it does still use JS. – pieman72 May 22 '12 at 15:21
  • I have added `alert('hello');` to the end of gwt file. It is executed without being locked by image loading, so the problem is not a race condition and gwt files are loaded and executed correctly. The problem probably is with events that gwt uses to start the app (call `onModuleLoad`). – Ali Shakiba May 22 '12 at 16:56
1

Since you're only having issues with local resources (duh!), I thought using a <base> as a plug would be a great idea:

<head>
    <base id="src-plug" href="http://src-plug/"/>
    <script>
        function unplug(){
            setTimeout(function(){//or whatever; I guess ondomready
                var srcPlug = document.getElementById('src-plug');
                srcPlug.parentNode.removeChild(srcPlug);
            },5000);
        }
    </script>
</head>

But apparently after having base removed, resources still need to be reloaded with something dorky like

$('img').each(function(){
    $(this).attr('src',$(this).attr('src'));
});

After about this point I realized this or any client-side workaround would not be a good idea

Instead, why don't you deliver content through a different subdomain, CDN-like? It's generally a good idea to have cookieless domains with custom caching policies etc. for static resources.

Oleg
  • 24,465
  • 8
  • 61
  • 91
1

There are two possible solutions I can think of:

1. xs linker

You could use the old "xs" linker instead of "xsiframe". This is not so nice, especially because xs doesn't work in dev mode. But maybe you could use xsiframe during development, and then switch to xs for the real builds, tests and production.

2. the <noscript> tag trick

You can put the page contents, especially the slowly loading images, into a <noscript> tag, which is used, if the browser doesn't support JavaScript.

If however JavaScript is enabled, then the contents of that tag are ignored during loading. So what we will do in our GWT code (which can use the xsiframe linker again), is to copy the contents of the noscript tag back into the real page.

Here's some quick code:

<!doctype html>

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

    <script type="text/javascript" language="javascript"
            src="http://cdn.example.org/.../some.nocache.js"></script>
  </head>

  <body>

    <noscript>
      <p>A</p>
      <img src="http://10.255.255.1/timeout.gif" alt="timeout image" />
      <p>B</p>
    </noscript>

    <p>Test (should appear immediately if JavaScript is enabled)</p>
  </body>
</html>
@Override
public void onModuleLoad() {

  final NodeList<Element> noscriptElems = 
      RootPanel.get().getElement().getElementsByTagName("noscript");

  final Element noscriptElem = noscriptElems.getItem(0);

  RootPanel.get().add(new Label("Here is GWT"));

  RootPanel.get().add(new HTMLPanel(noscriptElem.getInnerText()));
      /* Be careful of course, not to have bad html in your noscript elem */

}
Chris Lercher
  • 37,264
  • 20
  • 99
  • 131
0

I know this is a very old question, but it i still the top google hit, when searching for this issue.

And an alternate solution now is just to add loading="lazy" to images. (Not sure if that works for flash).

MTilsted
  • 5,425
  • 9
  • 44
  • 76