1

In my usecase, I am using both external and inline javascript contents. I have the following structure.

  app/
      header.html
      home.html
      config-load.js
      footer.html

home.html includes header.html and footer.html. header.html file includes config-load.js.

config-load.js makes an ajax call to get the configs based on the stage from golang backend. This may have few milliseconds delay.

There are few inline scripts in home.html which uses the configs collected by config-load.js ajax call.

So config-load.js ajax call must be completed before inline scripts are loaded. But it is loading in the other way around.

I tried to use a while loop to delay the load time for the inline scripts as below,

while(configReceived == false)
{
    setTimeout(function(){
    console.log("waiting for config");
    }, 2000);
}
if(configReceived)
{
    //process configs
}

But this blocks the thread. The page is stuck in the while loop. Is there any other way to achieve this?

EDIT 1 : Here is the inline script content,

  <script type="text/javascript">
    window.onload = function() {
        time = new Date($.now());
        var tagsArray = ["C", "C++", "Go", "Ruby"];
        //var tagsArray = [];
        requestJSON = '{"Method":"GET","AppName":"Web-app","ServiceURL":"'+endpoints.Tags.HTTPEndpoint.URL+'","Properties":null,"Object":"","Timestamp":"'+time+'"}'
        $.ajax({
        type: "GET",
        url: endpoints.Tags.HTTPEndpoint.URL,
        data: requestJSON,
        processData: false,
        contentType: "application/json;",
        dataType: "json",
        async: false,
        success: function(data){
          console.log("tags retrieved successfully info updated successfully")
          console.log("Tags ", data.Object)
          tagsArray = data.Object
        },
        failure: function(errMsg) {
            console.log("Error occured in getting tags ", errMsg)
        }
        });
        $("#myTags").tagit();
        $("#tags").tagit({
        fieldName: "tagsName", // The name of the hidden input field
        availableTags: tagsArray,
        allowSpaces:true,
        caseSensitive:false,
        removeConfirmation:true,
        placeholderText:"Tags",
        tagLimit: 5,
        allowDuplicates: false,
        singleField: true, // Use a hidden input element with the fieldName name
        singleFieldDelimiter: ',', // Optional, default value is same.
        onlyAvailableTags: false
        });
    }
 </script>

And my config-load.js looks like below,

//////////////////////////////////////////////////////////
// code block to get the service endpoints by stage starts
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
  if (xhr.readyState == 4 && xhr.status == 200) {
      endpoints = JSON.parse(xhr.responseText);
      console.log("server endpoints be ", endpoints);
      configReceived = true;
  }
}
xhr.open("GET", "/config", true);
try {
  xhr.send();
} catch (err) {
  // handle error
  console.log("Error occured in getting the service endpoints. This may break all ajax services");
}
// code block to get the service endpoints by stage ends
////////////////////////////////////////////////////////

I am trying for last 3 days but no luck.

1
  • Try to put config-load.js and anotherscript.js in your footer.html Commented Jul 16, 2016 at 4:47

2 Answers 2

2

Be aware that javascript is asynchronous and you don't have full control over the loading sequences of the scripts, unless you are not using the async await new javascript feature or promises. But in your case is not really needed for these.

First thing you need to do is to include the config-load.js in the head section, right on the top, this way you have some guarantee that the file is loaded before the DOM is getting populated.

Another thing is to use the window.onload function inside the inline scripts, to force the browser to parse the scripts only after all the DOM structure has been constructed and fully populated.

So inside your html section wrap your function into the window.onload function callback:

<script type="text/javascript">
    window.onload = function() {
        while(configReceived == false)
        {
            setTimeout(function(){
            console.log("waiting for config");
            }, 2000);
        }
        if(configReceived)
        {
            //process configs
        }
    }
</script>

EDIT:

There are quite a few errors in your approach. First and foremost there is no need to call the ajax requests in two separate scripts. Using the above mentioned promise technique you can chain the responses. Here is a short example of how the jquery promises are working:

function first() {
   return $.ajax(...);
}

function second(data, textStatus, jqXHR) {
   return $.ajax(...);
}

function third(data, textStatus, jqXHR) {
   return $.ajax(...);
}

function main() {
    first().then(second).then(third);
}

Remember: a call in the chain group return the response. Which means that you can delegate the response to the next chain, which means that when the request has been resolved you can pass through the result to the next call.

Applying to your example when you receive the response by calling the endpoints service, you can pass the result as parameter to the next call, and this will be accessed only when the response from the first call will be resolved.

Check this fiddle as an example.

Applying this technique it's not needed needed anymore to check configReceived = true;.

Another thing you have to make sure is that jQuery is included before you are trying to call jQuery.ajax.

Here are some references about promises:

http://www.danieldemmel.me/blog/2013/03/22/an-introduction-to-jquery-deferred-slash-promise/ http://www.bitstorm.org/weblog/2012-1/Deferred_and_promise_in_jQuery.html https://davidwalsh.name/write-javascript-promises

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks Simo. I am using tag-it in inline script. When I do window load, it is giving me error like Uncaught TypeError: $(...).tagit is not a function. :(. Do you have any idea.
I'm afraid jquery is not loaded, that's why you are getting this error.
Yeah. When I remove window.onload, I dont see this error but the order is different. I am not sure what is the relation between these two.
I updated the inline and config-load.js contents. Do you get any idea from this?
1

"while loop" is synchronous, which means it will block the thread and makes whole application stuck.

Javascript async scripts's execution order is not guaranteed, so you should use the "callback" or in ES6 you can use promise, ES7 you can use async, await.

Anyway the better way is wrap your config-load.js javascript code in a function, if you use Jquery's ajax api, the code may looks like this:

function loadConfigAjax(callback){
   $.ajax({url: "http://myconfig", success: function(config){
    callback(config)
}});
}

And in your inline javascript may looks like this

<script type="text/javascript">
    window.onload = function() {
        var configReceived = function(config){
           //process configs
        };
        // pass the configReceived as callback
        // so that configReceived function will always be invoked after config received
        loadConfigAjax(configReceived);
    }
</script>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.