0

I have a series of JavaScript libraries that are saved into a single string and passed to my page. We're loading some 3rd party code and they have multiple functions we must put on our page, and due to the nature of our website the data for some of these libraries is not available until after the page has loaded (using socket.io to pass us the data).

An example of what one of these "libraries" the page recieves might look like the following...

//"myId123" is generated on the page, sent to the server, and the server returns with the following two script tags as a single string
<script src="https://my.3rdparty.com/path/to/script.js"></script>
<script>
    myFunction({id:"myId123")
</script>

(They are passed together as one string, then using jQuery I parse it into a collection of elements)

Where myFunction() is loaded from the script tag immediately above it (src=my.3rdparty.com/...).

To clarify, the order of operations is as follows...

  1. Page requested
  2. Page generated via Jade and sent to browser
  3. Page loaded by browser
  4. Session variables generated by front-end, sent to server
  5. Dynamic libraries generated on server (using data from front-end)
  6. Libraries sent to front-end
  7. Libraries appended to page

My problem is that currently myFunction() is running before my external script has finished loading/executing, breaking my page.

How can I force the first script tag to load and execute before the next one(s)? Note that for some 'libraries', the order may be reversed (i.e. myFunction2() should run before the external library should be run so that it can generate variables used by the external library). We can assume that the order in which they're given to us in the string is the order that we want them to execute.

UPDATE. I'm inserting my 'libraries' using the following function...

insertPixelLibs=function(libs){
    //libs is an array of these string-libraries
    for (var i=0;i<libs.length;i++){
        $('#libs_div').append($(libs[i]));
    }
}

using $() converts the string into a collection of valid HTML Elements, and they seem to be appending properly as elements and not text. The problem is as described, where myFunction() is not defined.

nickrenfo2
  • 85
  • 1
  • 10

1 Answers1

0

The way I solved this issue was by calling a recursive function that would add each segment at a time, one by one. Here's my example code

function insertLibraries(libs){
    //libs is an array containing strings of valid HTML Element(s)
    var myLib ="";
    for (var i=0;i<libs.length;i++){
        myLib = $(libs[i]);
        insertLib(myLib,0);
    }
};
function insertLib(lib,i){
    //lib will be a string containing the library tag(s) to be inserted
    $lib = $(lib);//Convert to collection of jQuery elements
    if (typeof i != "number")i=0;
    if (i>=$lib.length) return;//if we added the last one in this library, return
    var myLib = $($lib[i]);
    if (myLib.prop('nodeType')===undefined) return insertLib(lib,++i);//continue to next iteration if it's just a text node between tags
    var newElm = document.createElement(myLib.prop('tagName'));//create a new element of the correct type
    var src = myLib.attr('src');
    if (src){
        newElm.src = src;
        //"onload" doesn't fire for local libraries, so we only put it on the external ones
        newElm.onload = function(){
            insertLib(lib,++i)//when this finishes loading, insert the next one in it's group
        };
        document.getElementById("my_div").appendChild(newElm);
    }
    else{
        var newHtml = $('<div>').html(myLib.html()).text();//this funky line basically decodes the html
        //meaning "1 &amp; 2" will turn into "1 & 2"
        newElm.innerHTML=newHtml;//currently only sets the HTML as text, not as a valid HTML child
        document.getElementById("my_div").appendChild(newElm);
        insertLib(lib,++i);
    }
};
nickrenfo2
  • 85
  • 1
  • 10