Reputation: 1772
I have a javascript tag embedded in the <head>
of a webpage. In this script (served via Amazon Cloudfront) it does some processing and then if certain checks are set, appends another script to the document head. Here is an example of that embed:
var js = document.createElement('script');
js.src = 'http://cdn.mysite.com/script.js?cache_bust='+Math.random();
document.getElementsByTagName('head')[0].appendChild(js);
This works properly, however it's non-blocking meaning the webpage continues to load while that script is being appended to the head.
Is there any way to embed a script in a blocking manner so the webpage "hangs" while the new script is setup?
I was thinking about maybe moving the first script to just below the <body>
tag and then using document.write() the second script but I'd prefer to keep it in the <head>
.
Any ideas? Thanks!
Upvotes: 1
Views: 275
Reputation: 48516
Use something like this script loader I made:
var scriptLoader = [];
/*
* loads a script and defers a callback for when the script finishes loading.
* you can also just stack callbacks on the script load by invoking this method repeatedly.
*
* opts format: {
* url: the url of the target script resource,
* timeout: a timeout in milliseconds after which any callbacks on the script will be dropped, and the script element removed.
* callbacks: an optional array of callbacks to execute after the script completes loading.
* callback: an optional callback to execute after the script completes loading.
* before: an optional callback to execute before the script is loaded, only intended to be ran prior to requesting the script, not multiple times.
* success: an optional callback to execute when the script successfully loads, always remember to call script.complete at the end.
* error: an optional callback to execute when and if the script request fails.
* }
*/
function loadScript(opts) {
if (typeof opts === "string") {
opts = {
url: opts
};
}
var script = scriptLoader[opts.url];
if (script === void 0) {
var complete = function (s) {
s.status = "loaded";
s.executeCallbacks();
};
script = scriptLoader[opts.url] = {
url: opts.url,
status: "loading",
requested: new Date(),
timeout: opts.timeout || 10000,
callbacks: opts.callbacks || [opts.callback || $.noop],
addCallback: function (callback) {
if (!!callback) {
if (script.status !== "loaded") {
script.callbacks.push(callback);
} else {
callback();
}
}
},
executeCallbacks: function () {
$.each(script.callbacks, function () {
this();
});
script.callbacks = [];
},
before: opts.before || $.noop,
success: opts.success || complete,
complete: complete,
error: opts.error || $.noop
};
script.before();
$.ajax(script.url, {
timeout: script.timeout,
success: function () {
script.success(script);
},
error: function () {
script.error(); // .error should remove anything added by .before
scriptLoader[script.url] = void 0; // dereference, no callbacks were executed, no harm is done.
}
});
} else {
script.addCallback(opts.callback);
}
}
loadScript({
url: 'http://fiddle.jshell.net/js/lib/mootools-core-1.4.5-nocompat.js',
callback: function(){
alert('foo');
}
});
Generally speaking, you should be deferring execution, rather than blocking, giving your user an increased perceived page loading speed.
Upvotes: 1
Reputation: 71939
You're right, document.write
should work. As Dr.Molle mentioned in the comment, you can use inside the <head>
too (the <head>
is part of the document too!).
So:
<head>
<script>
var src = 'http://cdn.mysite.com/script.js?cache_bust='+Math.random();
document.write '<script src="">'+ src + '</scr' + 'ipt>';
</script>
</head>
The '</scr' + 'ipt>'
part is a precaution, browsers usually think the outer script block is being closed when they find </script>
, even if inside a string.
Upvotes: 1