Document.Createelement("Script") Synchronously

document.createElement( script ) synchronously

You can create your <script> element with an "onload" handler, and that will be called when the script has been loaded and evaluated by the browser.

var script = document.createElement('script');
script.onload = function() {
alert("Script loaded and ready");
};
script.src = "http://whatever.com/the/script.js";
document.getElementsByTagName('head')[0].appendChild(script);

You can't do it synchronously.

edit — it's been pointed out that, true to form, IE doesn't fire a "load" event on <script> tags being loaded/evaluated. Thus I suppose the next thing to do would be to fetch the script with an XMLHttpRequest and then eval() it yourself. (Or, I suppose, stuff the text into a <script> tag you add; the execution environment of eval() is affected by the local scope, so it won't necessarily do what you want it to do.)

editAs of early 2013, I'd strongly advise looking into a more robust script loading tool like Requirejs. There are a lot of special cases to worry about. For really simple situations, there's yepnope, which is now built into Modernizr.

Dynamically loading JavaScript synchronously

There is only one way to synchronously load and execute a script resource, and that is using a synchronous XHR

This is an example of how to do this

// get some kind of XMLHttpRequest
var xhrObj = createXMLHTTPObject();
// open and send a synchronous request
xhrObj.open('GET', "script.js", false);
xhrObj.send('');
// add the returned content to a newly created script tag
var se = document.createElement('script');
se.type = "text/javascript";
se.text = xhrObj.responseText;
document.getElementsByTagName('head')[0].appendChild(se);

But you shouldn't in general use synchronous requests as this will block everything else.
But that being said, there are of course scenarios where this is appropriate.

I would probably refactor the containing function into an asynchronous pattern though using an onload handler.

document.createElement('script') vs script src=

The <script src=...> blocks the browser while document.createElement('script') loads the JavaScript asynchronously; this is the primary reason.


The <script src=...> tag blocks browser from displaying rest of the page until the script is loaded and executed. This ensures that scripts are executed in correct order and any document.write() in that script work as expected. However this creates a laggy browsing experience for the user.

When the script is loaded asynchronously, the browser can download the script without blocking the page display. This improves the browsing experience dramatically.

To load the scripts asynchronously one can use HTML markup:

<script src="..." async defer></script>

The async attribute was introduced in HTML5 while the defer attribute can be added as a fallback for older versions of IE. This document describes how async and defer attribute work.

Alternately, one can use JavaScript to build a script tag:

var s = document.createElement('script');
s.src = "...";
document.getElementsByTagName("head")[0].appendChild(s);

JavaScript generated script tags work in most browsers even if they do not understand the async attribute or .async = true property.


About schemeless URIs (//example.com/script.js): schemeless URIs seem to work almost everywhere (see this question).

About the Google Analytics example: both old and new code use JavaScript to detect the protocol then load http://www. or https://ssl. which is not possible via HTML markup.

Load several scripts in certain order

Yes! There is. Use Promises and async/await

function loadScript(url) {
return new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = url
document.head.appendChild(script)
script.onload = () => resolve()
})
}

async function loadScripts() {
await loadScript('script1.js')
await loadScript('script2.js')
// ..
}

loadScripts().then(_ => console.log('All scripts loaded in specified order'))

document.createElement('script')... adding two scripts with one callback

I propose you to use some small loader which will chain and do stuff for you. For example like this one:

function loadScripts(array,callback){
var loader = function(src,handler){
var script = document.createElement("script");
script.src = src;
script.onload = script.onreadystatechange = function(){
script.onreadystatechange = script.onload = null;
handler();
}
var head = document.getElementsByTagName("head")[0];
(head || document.body).appendChild( script );
};
(function run(){
if(array.length!=0){
loader(array.shift(), run);
}else{
callback && callback();
}
})();
}

This script should help you to build the script tags and call your callback when all files are loaded. Invoke is pretty easy:

loadScripts([
"http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js",
"http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js"
],function(){
alert('All things are loaded');
});

Hope this will help

Executing script elements inserted with .innerHTML

The OP's script doesn't work in IE 7. With help from SO, here's a script that does:

exec_body_scripts: function(body_el) {
// Finds and executes scripts in a newly added element's body.
// Needed since innerHTML does not run scripts.
//
// Argument body_el is an element in the dom.

function nodeName(elem, name) {
return elem.nodeName && elem.nodeName.toUpperCase() ===
name.toUpperCase();
};

function evalScript(elem) {
var data = (elem.text || elem.textContent || elem.innerHTML || "" ),
head = document.getElementsByTagName("head")[0] ||
document.documentElement,
script = document.createElement("script");

script.type = "text/javascript";
try {
// doesn't work on ie...
script.appendChild(document.createTextNode(data));
} catch(e) {
// IE has funky script nodes
script.text = data;
}

head.insertBefore(script, head.firstChild);
head.removeChild(script);
};

// main section of function
var scripts = [],
script,
children_nodes = body_el.childNodes,
child,
i;

for (i = 0; children_nodes[i]; i++) {
child = children_nodes[i];
if (nodeName(child, "script" ) &&
(!child.type || child.type.toLowerCase() === "text/javascript")) {
scripts.push(child);
}
}

for (i = 0; scripts[i]; i++) {
script = scripts[i];
if (script.parentNode) {script.parentNode.removeChild(script);}
evalScript(scripts[i]);
}
};


Related Topics



Leave a reply



Submit