What is the best way to make sure javascript is running when page is fully loaded? If you mean "fully loaded" literally, i.e., all images and other resources downloaded, then you have to use an onload handler, e.g.: window. onload = function() { // Everything has loaded, so put your code here };
Under normal circumstances, a script tag causes the browser to halt rendering, load a file, and run the code. The browser is blocked from doing other useful work because your JavaScript could write to the page, modify existing elements, or redirect to another URL.
Synchronous loading of the scriptjs is loaded only when the loading of FirstScript. js is complete. Similarly, all requests are handled synchronously.
There is no error event for the script tag. You can tell when it is successful, and assume that it has not loaded after a timeout:
<script type="text/javascript" onload="loaded=1" src="....js"></script>
my working clean solution (2017)
function loaderScript(scriptUrl){
return new Promise(function (res, rej) {
let script = document.createElement('script');
script.src = scriptUrl;
script.type = 'text/javascript';
script.onError = rej;
script.async = true;
script.onload = res;
script.addEventListener('error',rej);
script.addEventListener('load',res);
document.head.appendChild(script);
})
}
As Martin pointed, used like that:
const event = loaderScript("myscript.js")
.then(() => { console.log("loaded"); })
.catch(() => { console.log("error"); });
OR
try{
await loaderScript("myscript.js")
console.log("loaded");
}catch{
console.log("error");
}
UPDATE 2021:
All browsers today support onerror=""
on script tags, examples:
<script src="nonexistent.js" onerror="alert('error!')"></script>
Original comment from 2010:
If you only care about html5 browsers you can use error event.
From the spec:
If the src attribute's value is the empty string or if it could not be resolved, then the user agent must queue a task to fire a simple event named error at the element, and abort these steps.
(...)
If the load resulted in an error (for example a DNS error, or an HTTP 404 error) Executing the script block must just consist of firing a simple event named error at the element.
This means you don't have to do any error prone polling and can combine it with async and defer attribute to make sure the script is not blocking page rendering:
The defer attribute may be specified even if the async attribute is specified, to cause legacy Web browsers that only support defer (and not async) to fall back to the defer behavior instead of the synchronous blocking behavior that is the default.
More on http://www.w3.org/TR/html5/scripting-1.html#script
The script from Erwinus works great, but isn't very clearly coded. I took the liberty to clean it up and decipher what it was doing. I've made these changes:
prototype
.require()
uses an argument variablealert()
messages are returned by defaultThanks again to Erwinus, the functionality itself is spot on.
function ScriptLoader() {
}
ScriptLoader.prototype = {
timer: function (times, // number of times to try
delay, // delay per try
delayMore, // extra delay per try (additional to delay)
test, // called each try, timer stops if this returns true
failure, // called on failure
result // used internally, shouldn't be passed
) {
var me = this;
if (times == -1 || times > 0) {
setTimeout(function () {
result = (test()) ? 1 : 0;
me.timer((result) ? 0 : (times > 0) ? --times : times, delay + ((delayMore) ? delayMore : 0), delayMore, test, failure, result);
}, (result || delay < 0) ? 0.1 : delay);
} else if (typeof failure == 'function') {
setTimeout(failure, 1);
}
},
addEvent: function (el, eventName, eventFunc) {
if (typeof el != 'object') {
return false;
}
if (el.addEventListener) {
el.addEventListener(eventName, eventFunc, false);
return true;
}
if (el.attachEvent) {
el.attachEvent("on" + eventName, eventFunc);
return true;
}
return false;
},
// add script to dom
require: function (url, args) {
var me = this;
args = args || {};
var scriptTag = document.createElement('script');
var headTag = document.getElementsByTagName('head')[0];
if (!headTag) {
return false;
}
setTimeout(function () {
var f = (typeof args.success == 'function') ? args.success : function () {
};
args.failure = (typeof args.failure == 'function') ? args.failure : function () {
};
var fail = function () {
if (!scriptTag.__es) {
scriptTag.__es = true;
scriptTag.id = 'failed';
args.failure(scriptTag);
}
};
scriptTag.onload = function () {
scriptTag.id = 'loaded';
f(scriptTag);
};
scriptTag.type = 'text/javascript';
scriptTag.async = (typeof args.async == 'boolean') ? args.async : false;
scriptTag.charset = 'utf-8';
me.__es = false;
me.addEvent(scriptTag, 'error', fail); // when supported
// when error event is not supported fall back to timer
me.timer(15, 1000, 0, function () {
return (scriptTag.id == 'loaded');
}, function () {
if (scriptTag.id != 'loaded') {
fail();
}
});
scriptTag.src = url;
setTimeout(function () {
try {
headTag.appendChild(scriptTag);
} catch (e) {
fail();
}
}, 1);
}, (typeof args.delay == 'number') ? args.delay : 1);
return true;
}
};
$(document).ready(function () {
var loader = new ScriptLoader();
loader.require('resources/templates.js', {
async: true, success: function () {
alert('loaded');
}, failure: function () {
alert('NOT loaded');
}
});
});
I know this is an old thread but I got a nice solution to you (I think). It's copied from an class of mine, that handles all AJAX stuff.
When the script cannot be loaded, it set an error handler but when the error handler is not supported, it falls back to a timer that checks for errors for 15 seconds.
function jsLoader()
{
var o = this;
// simple unstopable repeat timer, when t=-1 means endless, when function f() returns true it can be stopped
o.timer = function(t, i, d, f, fend, b)
{
if( t == -1 || t > 0 )
{
setTimeout(function() {
b=(f()) ? 1 : 0;
o.timer((b) ? 0 : (t>0) ? --t : t, i+((d) ? d : 0), d, f, fend,b );
}, (b || i < 0) ? 0.1 : i);
}
else if(typeof fend == 'function')
{
setTimeout(fend, 1);
}
};
o.addEvent = function(el, eventName, eventFunc)
{
if(typeof el != 'object')
{
return false;
}
if(el.addEventListener)
{
el.addEventListener (eventName, eventFunc, false);
return true;
}
if(el.attachEvent)
{
el.attachEvent("on" + eventName, eventFunc);
return true;
}
return false;
};
// add script to dom
o.require = function(s, delay, baSync, fCallback, fErr)
{
var oo = document.createElement('script'),
oHead = document.getElementsByTagName('head')[0];
if(!oHead)
{
return false;
}
setTimeout( function() {
var f = (typeof fCallback == 'function') ? fCallback : function(){};
fErr = (typeof fErr == 'function') ? fErr : function(){
alert('require: Cannot load resource -'+s);
},
fe = function(){
if(!oo.__es)
{
oo.__es = true;
oo.id = 'failed';
fErr(oo);
}
};
oo.onload = function() {
oo.id = 'loaded';
f(oo);
};
oo.type = 'text/javascript';
oo.async = (typeof baSync == 'boolean') ? baSync : false;
oo.charset = 'utf-8';
o.__es = false;
o.addEvent( oo, 'error', fe ); // when supported
// when error event is not supported fall back to timer
o.timer(15, 1000, 0, function() {
return (oo.id == 'loaded');
}, function(){
if(oo.id != 'loaded'){
fe();
}
});
oo.src = s;
setTimeout(function() {
try{
oHead.appendChild(oo);
}catch(e){
fe();
}
},1);
}, (typeof delay == 'number') ? delay : 1);
return true;
};
}
$(document).ready( function()
{
var ol = new jsLoader();
ol.require('myscript.js', 800, true, function(){
alert('loaded');
}, function() {
alert('NOT loaded');
});
});
To check if the javascript in nonexistant.js
returned no error you have to add a variable inside http://fail.org/nonexistant.js
like var isExecuted = true;
and then check if it exists when the script tag is loaded.
However if you only want to check that the nonexistant.js
returned without a 404 (meaning it exists), you can try with a isLoaded
variable ...
var isExecuted = false;
var isLoaded = false;
script_tag.onload = script_tag.onreadystatechange = function() {
if(!this.readyState ||
this.readyState == "loaded" || this.readyState == "complete") {
// script successfully loaded
isLoaded = true;
if(isExecuted) // no error
}
}
This will cover both cases.
I hope this doesn't get downvoted, because in special circumstances it is the most reliable way to solve the problem. Any time the server allows you to get a Javascript resource using CORS (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing), you have a rich array of options to do so.
Using XMLHttpRequest to fetch resources will work across all modern browsers, including IE. Since you are looking to load Javascript, you have Javascript available to you in the first place. You can track the progress using the readyState (http://en.wikipedia.org/wiki/XMLHttpRequest#The_onreadystatechange_event_listener). Finally, once you receive the content of the file, you can execute it with eval ( ). Yes, I said eval -- because security-wise it is no different from loading the script normally. In fact, a similar technique is suggested by John Resig to have nicer tags (http://ejohn.org/blog/degrading-script-tags/).
This method also lets you separate the loading from the eval, and execute functions before and after the eval happens. It becomes very useful when loading scripts in parallel but evaluating them one after the other -- something browsers can do easily when you place the tags in HTML, but don't let you by adding scripts at run-time with Javascript.
CORS is also preferable to JSONP for loading scripts (http://en.wikipedia.org/wiki/XMLHttpRequest#Cross-domain_requests). However, if you are developing your own third-party widgets to be embedded in other sites, you should actually load the Javascript files from your own domain in your own iframe (again, using AJAX)
In short:
Try to see if you can load the resource using AJAX GET
Use eval after it has successfully loaded
To improve it:
Check out the cache-control headers being sent
Look into otherwise caching the content in localStorage, if you need to
Check out Resig's "degrading javascript" for cleaner code
Check out require.js
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