I have a script that knows to load dynamiclly scripts that contains javascript classes. i'm loading the class script using the following code:
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "myscript.js";
head.appendChild(script);
i'm then trying to create the new class using eval:
var classObj = eval(" new MyClass()" );
the problem is that the code of the eval is being executed bofre the script has been loaded into memory and i get an error that the MyClass is undefined.
Is there a way to synch these events? i need to make sure the script is fully being loaded into memory before i can start allocating classes from it.
We start by creating an empty <script></script> tag in the memory as script and then assign the necessary attributes to its src and the id to identify the script later. Finally, we append the script to our <body></body> tag to actually load this.
If you cannot do that for some reason, then you can delay the loading of the external script file like this: setTimeout(function() { var headID = document. getElementsByTagName("head")[0]; var newScript = document. createElement('script'); newScript.
Script tags are executed in the order they appear It also means scripts which appear later on the page can depend on things scripts which appear earlier have done. Elements on the page won't render until all the script tags preceding them have loaded and executed.
To kick your JavaScript skills into outer space, everything you see here and more (with all its casual clarity!) is available in both paperback and digital editions. For loading a script file dynamically using JavaScript, the basic steps are: Set the src attribute on the script element to point to the file we want to load
It still applies, and constructive comments are welcome on any gaffes or oversights. When a JavaScript source file is included in a web page via HTML’s ‘<script>’ tag, the loading of the included file is performed to completion before any more of the including page is rendered/executed. That’s what synchronous loading is.
The only (see caveat) way to achieve the OPs question is to sync load the script over XHR as stated, then read as text and pass into either eval () or a new Function () call and wait for that function to return. This is the only way to guarantee the script is loaded AND executed synchronously.
Moreover, a loaded script may load more scripts, which defers the queue in the parent script. BTW, a script here means a JavaScript file or a CSS stylesheet. // Load a single script Loader.add ( { src: 'test.js', onload: function () { alert ('yay!');
You need to attach an event handler to either the onload method, in browsers compliant with Web standards, or the onreadystatechange, checking for the script.readyState property getting equal to "loaded" or "complete", in Internet Explorer.
Before you get notified that the script was loaded, you are probably trying to access objects, functions and properties that have not been declared or created yet.
Here is an example function, extracted from the module bezen.dom.js in my Javascript library, bezen.org:
var appendScript = function(parent, scriptElt, listener) {
// append a script element as last child in parent and configure
// provided listener function for the script load event
//
// params:
// parent - (DOM element) (!nil) the parent node to append the script to
// scriptElt - (DOM element) (!nil) a new script element
// listener - (function) (!nil) listener function for script load event
//
// Notes:
// - in IE, the load event is simulated by setting an intermediate
// listener to onreadystate which filters events and fires the
// callback just once when the state is "loaded" or "complete"
//
// - Opera supports both readyState and onload, but does not behave in
// the exact same way as IE for readyState, e.g. "loaded" may be
// reached before the script runs.
var safelistener = catchError(listener,'script.onload');
// Opera has readyState too, but does not behave in a consistent way
if (scriptElt.readyState && scriptElt.onload!==null) {
// IE only (onload===undefined) not Opera (onload===null)
scriptElt.onreadystatechange = function() {
if ( scriptElt.readyState === "loaded" ||
scriptElt.readyState === "complete" ) {
// Avoid memory leaks (and duplicate call to callback) in IE
scriptElt.onreadystatechange = null;
safelistener();
}
};
} else {
// other browsers (DOM Level 0)
scriptElt.onload = safelistener;
}
parent.appendChild( scriptElt );
};
To adapt it to your needs, you may replace the call to catchError, which wraps the listener to catch and log errors, and use the modified function:
var appendScript = function(parent, scriptElt, listener) {
// append a script element as last child in parent and configure
// provided listener function for the script load event
//
// params:
// parent - (DOM element) (!nil) the parent node to append the script to
// scriptElt - (DOM element) (!nil) a new script element
// listener - (function) (!nil) listener function for script load event
//
// Notes:
// - in IE, the load event is simulated by setting an intermediate
// listener to onreadystate which filters events and fires the
// callback just once when the state is "loaded" or "complete"
//
// - Opera supports both readyState and onload, but does not behave in
// the exact same way as IE for readyState, e.g. "loaded" may be
// reached before the script runs.
var safelistener = function(){
try {
listener();
} catch(e) {
// do something with the error
}
};
// Opera has readyState too, but does not behave in a consistent way
if (scriptElt.readyState && scriptElt.onload!==null) {
// IE only (onload===undefined) not Opera (onload===null)
scriptElt.onreadystatechange = function() {
if ( scriptElt.readyState === "loaded" ||
scriptElt.readyState === "complete" ) {
// Avoid memory leaks (and duplicate call to callback) in IE
scriptElt.onreadystatechange = null;
safelistener();
}
};
} else {
// other browsers (DOM Level 0)
scriptElt.onload = safelistener;
}
parent.appendChild( scriptElt );
};
Since you seem to be able to edit the external script (since you tested it with an alert), why not just put this code in that script?
If you can't do that (maybe the extra code is generated or the first file is shared perhaps), just add a function call at the end of the script you're loading like this:
load_complete();
and then put your extra code in that function:
function load_complete() {
var classObj = eval(" new MyClass()" );
}
It's a lot simpler and foolproof than any kind of onload trigger. Also, if the js file is shared, then you can have different load_complete functions on every page that uses it (just be sure to always define a load_complete, even if it is empty).
I believe that this can actually be remedied by making sure you put the code loading the external script and the code using the external script separate script blocks like this:
<script>
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "myscript.js";
head.appendChild(script);
//this is in the same script block so it wouldn't work
//var classObj = eval(" new MyClass()" );
</script>
<script>
//this is in a separate script block so it will work
var classObj = eval(" new MyClass()" );
</script>
Use the jQuery (a JavaScript library) getScript function to load your script async. Use the callback function to create your objects. Example:
$.getScript("script.js", function () { var classObj = new MyClass(); });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With