Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    How to implement asynchronous / deferred Javascript loading with SmartGWT?

    Hi,

    I'm using SmartGWT 2.4 LGPL for a free application deployed on GAE.

    The problem is that the home page takes a while to load. Of course, after all the components are downloaded to the client, the performance is really good. I've read the forum posts on people complaining about the large SmartGWT Javascript file sizes and the time it takes to download them. Personally, I'm "not" complaining as I'm happy with all the functionality I get in return. I've also read Isomorphic's response to those posts and followed their suggestions such as compression, caching, stripping out unused scripts (using the "SmartGWTNoScript" module approach from the Showcase) etc.

    Now what I'm trying to achieve is to reduce the load time for the "home page" of my application. As a first step, I created a simple HTML home page without any SmartGWT components. After the user logs in, the SmartGWT widgets load up, and everything works fine.

    The next step is to improve the load time for the home page by deferring the SmartGWT Javascripts download until the user logs in. I really don't mind the time it takes to download the Javascripts after the user logs in. I'm displaying the Showcase-like "Loading ..." message while the SmartGWT components load on the screen.

    I also understand that SmartGWT has a OOTB functionality (FileUpload) to achieve something similar, but it's available only in the Pro and higher versions (which I'll be considering in future).

    From the investigation I've done so far, I have stumbled upon 2 problems:

    1. I found that even for a blank HTML page to display, I need Isc_Core.js and Isc_Databinding.js to be loaded up front. I know the specific order in which these files need to be included, but just for experimentation sake I loaded those two files, and my home page loaded up.

    If I don't include Isc_Core.js, I get an error from SmartGwtEntryPoint -> init() call. If I don't include Isc_Databinding.js, I get another error (something related to a reference to RPCManager).

    2. Once the user logs in, I'm trying to load all the required Javascripts using an approach somewhat similar to the one mentioned in this thread ( http://forums.smartclient.com/showthread.php?p=37803#post37803 ) and running into some problems with load_skin.js (as mentioned on that thread as well). I need to do more investigation into this.

    -------------

    At this point, my question is whether my idea of having a plain home page without loading any SmartGWT Javascripts, even viable or am I trying to achieve something which is not possible / not recommended.

    If my approach is reasonable, is there something I can do to overcome problem #1?

    I'll really appreciate any help on this.

    Thanks.

    #2
    I feel more assured after reading this in the Quick Start Guide:

    Although it is straightforward to build a login interface in Smart GWT, it
    is generally recommended that you implement your login page as a plain
    HTML page, due to the following advantages:

    - interoperable/single sign-on capable —if your application
    may need to participate in single sign-on environment (even
    in the distant future), you will be in a better position to
    integrate if you are making minimal assumptions about the
    technology and implementation of the login page

    - login page appears instantly—the user does not have to wait
    for the entire application to download in order to see the
    login page and begin entering credentials

    - background loading – use techniques such as off-screen
    <img> tags and <script defer=true/> tags to begin loading
    your application while the user is typing in credentials
    This tells me that what I'm trying to achieve is not unreasonable. I'll try to implement some of the suggestions mentioned in the guide. From what I remember, defer=true doesn't work on all browsers, but it should help to some extent. I'll implement it and report the results.

    Apart from these, is it possible to completely defer loading any SmartGWT components until after the login?

    Thanks.

    Comment


      #3
      Yes - what the QuickStart Guide is telling you to do is have a login page in which SmartGWT is not referenced at all. Just plain HTML. That page can use various techniques to begin caching the files that your application needs to load (ISC_Core.js et al).

      Comment


        #4
        Hello Isomorphic,

        Thanks for your response.

        I've already got a pure HTML home page in place. If I load the scripts the normal way, everything works. But I've not been able to get it working with deferred loading. I've tried at least 3 different approaches to load the ISC*.js, but haven't been able to get them working correctly. Let me describe the problems in detail:

        1. The ISC*.js files have dependencies among each other and hence cannot be loaded by using simple asynchronous loading techniques. For example, if ISC_Forms.js gets loaded before ISC_Core.js, it will complain that "isc" is not defined.

        2. Next, I tried using an "ordered" asynchronous loading technique and loaded all the ISC*.js files. At the end, I try to load "load_skin.js", but somehow it fails. Basically, the skin doesn't get applied properly (sometimes some images are missing, and sometimes all images are missing). The other functionalities seem to work fine.

        3. I tried using "defer='true'" property for loading the ISC*.js as suggested in the Guide, but that didn't work either. If I understand it correctly, there's no guarantee that the order of loading the scripts would be maintained (please correct me if I'm wrong). So this approach has the same problem as #1.

        I would be really thankful if you could suggest some technique(s) to help overcome these issues. I've tried searching the forum but haven't found much information related to this.

        Thanks.

        Comment


          #5
          We don't know about #2 (sounds like just a coding error of some kind), but yes, it's hard to get right, and the correct technique varies by browser. That's why it's part of Power licenses. But we'll give you a hint: it's better to just cause the .js to be loaded, and hence cached, but not actually execute it, since you won't even be using it on this page.

          Comment


            #6
            Hello Isomorphic,

            I think I got the hint. I understand your constraints too.

            I'm making some progress. Since I'm not really a Javascript expert, it's taking me a while. But it's a good learning experience.

            I'm facing one problem right now related to SmartGwtEntryPoint. It gets called before my EntryPoint and has JSNI code that depends upon at least ISC_Core.js and ISC_Databinding.js. Therefore, I have to load at least those 2 files before being able to even display the home page.

            So, is there any way I can avoid loading those 2 files upfront before getting to my home page?

            Thanks for supporting me on this effort.

            Comment


              #7
              What do you mean by the homepage? Again the login page, which is where you want to do your pre-loading, should not involve GWT or SmartGWT at all. If by the homepage you mean the page the user arrives at *after* logging in, the first action you take in SmartGWT (JSNI or otherwise) is going to require those foundation .js files.

              Comment


                #8
                Hello Isomorphic,

                Your question was the answer for me :) I was making a fundamental mistake. I had just one HTML page in my application and that was my bootstrap HTML file. Initially I would use it as a home page (the welcome page shown to new/non-logged-in users). This page had a "Log In" button and had no GWT or SmartGWT components. Subsequently, after successful login, I would replace the HTML components with the SmartGWT components in the same HTML file by DOM manipulation. But it had a call to *.nocache.js that was invoking SmartGWTEntryPoint.

                Now I've fixed all that. I've created a new HTML file (call it index.html) that serves as my home page (welcome file). It doesn't call *.nocache.js and hence doesn't need any GWT or SmartGWT components. The main bootstrap HTML file (call it main.html) remains in place as usual. Inside index.html, I use an ordered asynchronous loading technique to load all the SmartGWT .js files. The page loads really fast and the controls are available in less than 5 secs. The .js files continue to download in the background. When the user logs in, the control is redirected to main.html and the .js files are pulled from the cache. All the SmartGWT components load up pretty quickly on main.html. Everything works perfectly, well at least that's what I thought until this morning when I discovered a new issue.

                If I click on the "Log In" button too soon (let's say as soon as it's available), the async downloads break. After the user logs in, the SmartGWT components do not load, and I see a huge bunch of "SyntaxError: Unexpected end of input" errors in the Firebug console. When I look at the .js files, they are incomplete.

                So, is it possible to somehow check on the main.html whether the .js files are complete? If they are not complete, then download them again. If they are complete, then continue as usual. I will investigate into this today, but I can certainly do with a small piece of your knowledge.

                Thanks for supporting me throughout with your incisive comments.

                Comment


                  #9
                  I deepfriedbrain,
                  you could post the html files, I have done such a thing, making calls to gwt modules in a different page of that login. But I do not understand what you mean by loading cache.
                  In practice I've only index html in a form with the request, if true answers in a html page with redirects all calls to the modules and smartgwt and nocache.js

                  Originally posted by deepfriedbrain
                  Hello Isomorphic,

                  Your question was the answer for me :) I was making a fundamental mistake. I had just one HTML page in my application and that was my bootstrap HTML file. Initially I would use it as a home page (the welcome page shown to new/non-logged-in users). This page had a "Log In" button and had no GWT or SmartGWT components. Subsequently, after successful login, I would replace the HTML components with the SmartGWT components in the same HTML file by DOM manipulation. But it had a call to *.nocache.js that was invoking SmartGWTEntryPoint.

                  Now I've fixed all that. I've created a new HTML file (call it index.html) that serves as my home page (welcome file). It doesn't call *.nocache.js and hence doesn't need any GWT or SmartGWT components. The main bootstrap HTML file (call it main.html) remains in place as usual. Inside index.html, I use an ordered asynchronous loading technique to load all the SmartGWT .js files. The page loads really fast and the controls are available in less than 5 secs. The .js files continue to download in the background. When the user logs in, the control is redirected to main.html and the .js files are pulled from the cache. All the SmartGWT components load up pretty quickly on main.html. Everything works perfectly, well at least that's what I thought until this morning when I discovered a new issue.

                  If I click on the "Log In" button too soon (let's say as soon as it's available), the async downloads break. After the user logs in, the SmartGWT components do not load, and I see a huge bunch of "SyntaxError: Unexpected end of input" errors in the Firebug console. When I look at the .js files, they are incomplete.

                  So, is it possible to somehow check on the main.html whether the .js files are complete? If they are not complete, then download them again. If they are complete, then continue as usual. I will investigate into this today, but I can certainly do with a small piece of your knowledge.

                  Thanks for supporting me throughout with your incisive comments.
                  Thanks

                  Comment


                    #10
                    Isn't this solution suitable for you?

                    in login.jsp
                    Code:
                    <script type="text/javascript" defer="defer" src="<c:url value='/mymodulename/sc/modules/ISC_Core.js'/>"></script>
                    <script type="text/javascript" defer="defer" src="<c:url value='/mymodulename/sc/modules/ISC_Foundation.js'/>"></script>
                    <script type="text/javascript" defer="defer" src="<c:url value='/mymodulename/sc/modules/ISC_Containers.js'/>"></script>
                    <script type="text/javascript" defer="defer" src="<c:url value='/mymodulename/sc/modules/ISC_Grids.js'/>"></script>
                    <script type="text/javascript" defer="defer" src="<c:url value='/mymodulename/sc/modules/ISC_Forms.js'/>"></script>
                    <script type="text/javascript" defer="defer" src="<c:url value='/mymodulename/sc/modules/ISC_RichTextEditor.js'/>"></script>
                    <script type="text/javascript" defer="defer" src="<c:url value='/mymodulename/sc/modules/ISC_Calendar.js'/>"></script>
                    <script type="text/javascript" defer="defer" src="<c:url value='/mymodulename/sc/modules/ISC_DataBinding.js'/>"></script>
                    Add more .js files as you need them.

                    If I click on the "Log In" button too soon (let's say as soon as it's available), the async downloads break
                    Break? What do you mean by break? If the browser was not able to cache .js files it'll just do it on the next page. He doesn't care about such things.

                    No cache - load, Cache present and 304 from server - do not load. It's all that simple.

                    What is more complicated and what worries me is cache update on smartclient js libraries update.

                    You can't just load something like ISC_Core.js?ver=123, because on the smartgwtpage SmartGwtLinker links scripts without any parameters, so they're always loaded with it's original name. I'm not deep enough in the problem yet and if anyone can provide a good solution to updating SC libraries on client at the right time, that'd be great.

                    BTW, it's interesting, how SmartGwt itself handles this situation without Power version and FileLoader.

                    Do web apps with Pro and LGPL lecense suffer from this issue? And clients have to clear their cache manually?

                    Comment

                    Working...
                    X