1

When you have code like this:

var scriptNode = document.createElement('script');
scriptNode.type = 'text/javascript';
scriptNode.charset = 'utf-8';
scriptNode.onload = function() {
    console.log("Finished Loading Script");
   //do stuff here
}
scriptNode.async = false;
scriptNode.src = "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js";
document.getElementsByTagName('body')[0].appendChild(scriptNode);

it is not actually true that the external script has executed and therefore stuff is ready to do at the onload point. Am I right in saying that onload does not mean "after the browser has processed and executed the JS and the external JS objects are ready to use"?

If this is true, is there a way to check that the browser has executed the script? I've tried using document.currentScript and that does not seem to deal with the execution delay.

Note that the jquery is just an example, I know that I can check for jquery using window.jQuery or typeof The situation I'm interested in is where you don't know what objects may be available after execution, where you're blind to the contents of the external script.

One approach I have been looking into is using Promises. In the following code, I set up a promise (the content of which does not really matter) and then get the promise to report.

function findScriptNode(source) {
    return new Promise(function(resolve) {
        var scripts = document.getElementsByTagName("script");
        for (var i=0;i<scripts.length;i++) {
            if (scripts[i].src && scripts[i].src === source) {
              var timestamp = Date.now();
              var finetimestamp = performance.now();
              console.log(source + " Promise Event Timestamp: " + timestamp + " Performance Timestamp: "  + finetimestamp);
              resolve();
              break;
            }
        }
    });
}

var source = "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js";
var scriptNode = document.createElement('script');
scriptNode.type = 'text/javascript';
scriptNode.charset = 'utf-8';
scriptNode.onload = function() {
      var timestamp = Date.now();
      var finetimestamp = performance.now();
      console.log(source + " Load Event Timestamp: " + timestamp + " Performance Timestamp: "  + finetimestamp);
      findScriptNode(source).then(success => { 
          timestamp = Date.now();
          finetimestamp = performance.now();
          console.log(source + " Promise Complete Event Timestamp: " + timestamp + " Performance Timestamp: "  + finetimestamp);
      });
}
scriptNode.async = false;
scriptNode.src = source
document.getElementsByTagName('body')[0].appendChild(scriptNode);

With my limited understanding of the internals of Chrome JS execution, my understanding is that the following will happen in this order

  1. Script Tag created
  2. External Script Loaded
  3. Promise created and control handed back to the browser
  4. Browser will then continue executing the downloaded external script
  5. Once that execution has finished, the promise will resolve

It would have the advantage of waiting for the external script to execute (which may itself call loads of other scripts). Does that make any sense to anyone?

Any answers gratefully received.

Tom
  • 1,447
  • 1
  • 12
  • 26
  • Not unless the library itself provides a mechanism to call a function whenever it is loaded. – zero298 Apr 21 '17 at 18:18
  • `$( window ).on( "load", function() { ... })` will run when all resources are loaded. For non-jQuery: `window.onload = function(){}` can be used. [The jquery documentation](https://learn.jquery.com/using-jquery-core/document-ready/). – Thakkie Apr 21 '17 at 18:19
  • @Thakkie this script is loaded asynchronously. – zero298 Apr 21 '17 at 18:20
  • Sorry yes I should have mentioned that I know that, if it's jquery (for example), then I can use typeof to check that it's ready. The question I'm asking is when I don't know what objects to expect, can I work out when the external script has been executed? – Tom Apr 21 '17 at 18:23
  • Ow, sorry. I failed to correctly read the question. For this specific situation with jQuery, you can check for the existence the global jQuery variable. `if (typeof jQuery == 'undefined') ` – Thakkie Apr 21 '17 at 18:25
  • This post might have some useful info. [Javascript dynamic script loading via functions… how to do onload or readyState all over again?](http://stackoverflow.com/questions/32847752/javascript-dynamic-script-loading-via-functions-how-to-do-onload-or-readystat) – Thakkie Apr 21 '17 at 18:37

1 Answers1

2

You can do the following:

// initial call
setTimeout(function(){ checkJquery(); }, 3000);


function checkJquery() {
    if (window.jQuery) {  
        // jQuery is loaded  
        alert("Yeah!");
    } else {
        // jQuery is not loaded, check again in 3 seconds
        setTimeout(function(){ checkJquery(); }, 3000);
    }
}

Last but not least, you will need to define after how many iterations an error message should be displayed to the user.

EDIT:

For any other script, you can check a given method "myFunction" was loaded or a given variable like this:

if (typeof myFunction === "function") { 

}

if (myVariable) {

}
VirtualTroll
  • 3,077
  • 1
  • 30
  • 47