fetch a fallback copy of a remote script when its CDN fails - javascript

I have a Google +1 button on my site that requires the following script:
<script src="https://apis.google.com/js/platform.js" async defer></script>
The problem is as of today, apis.google.com can't be pinged from everywhere (servers are down) and some of my users don't see a button. I don't always want to use my own copy of the script because I can see that breaking the +1 functionality at some point. I'd like to use something like the solution from this question: my server's fallback copy should be fetched only when the CDN fails.
What's a good way to do that for this script? Is there a generic way to do this for any remote script using jQuery or plain js? Thanks in advance.
EDIT:
I tried jQuery getScript() and wrapped it in a function like this:
function fetch_script(script,fallback) {
$.getScript( script )
.fail(function() {
$.getScript( fallback );
});
};
This does not always work and is not reliable. Two problems I found:
500 errors trigger the fail method, but 404 errors do not and the fallback script is not loaded in these cases. Not sure what happens if the server is just down.
Some scripts are fetched (I see this in the console) but are somehow not executed (or they fail silently). Here's a script that doesn't work.

Related

phantomJS includeJs method always fails to load script via Operation Cancelled

I'm trying to load some scripts into my pages being visited by phantomjs. I'm using 2.1.1 btw.
I'm kind of banging my head here because I've tried a variety of things and they all seem to fail in the same way which kind of makes me think maybe I'm missing a configuration setting or something.
Any who what I'm trying :
//I dont actually care about using jquery, just trying loading from different servers
page.includeJs('http://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js');
and
page.includeJs('https://aSiteIControl.com/jquery.min.js');
and then I have a onResourceError handler like this:
page.onResourceError = function(resourceError) {
console.error(resourceError.url + ': ' + resourceError.errorString);
console.error(JSON.stringify(resourceError))
};
that outputs this no matter what I've tried:
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js: Operation canceled
{"errorCode":5,"errorString":"Operation canceled","id":1,"status":null,"statusText":null,"url":"https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"}
This seems to happen no matter what protocol I use or what server the script lives on. Also, both of those examples are visitable in a browser. Any body have any idea what I might be doing wrong?
TO BE CLEAR on the accepted answer since there is no code:
just go look at this question :
PhantomJS: injecting a script before any other scripts run
I bet you can include directly only local scripts. Please try:
(page.evaluate(function() {
var script = document.createElement('script');
script.src = 'http://urlToScript.com';
}))
This can be caused by a timeout or the call to the exit() function of the phantom object while the js is being loaded, or if you try to open another page. Can you add all your code?
Based on the documentation you can include external JS:
Includes external script from the specified url (usually a remote location)

Does failing to load a remote javascript file stop javascript execution in any browsers?

I've got a stand alone script file that I want to load from a 3rd party server:
<script type="text/javascript" src="//some_server/logger.js"></script>
There's a small chance the remote script won't be there sometimes (404), and I want to be sure that including this script doesn't affect how my app operates, since my app doesn't require the script to be loaded to work (it's an analytics tracker of sorts)
Can I include this script safely without it blocking or causing javascript errors in my app that stops other javascript from running?
I was thinking of adding the async and defer attributes to make the script load lazily. Is this enough? My app needs to work on IE8 and above.
Here's what I'm thinking right now:
<script async defer type="text/javascript" src="//some_server/logger.js"></script>
<script type="text/javascript">
console.log("I want this to always execute, no matter if the above script 404's or not!");
</script>
Can I include this script safely without it blocking or causing
javascript errors in my app that stop other javascript from running?
YES you can
A 404 does not halt execution of javascript in any way, only errors do.
As long as the server responds with a 404, and doesn't hang, the script not loading won't cause any noticeable delay.
This can be tested in different browsers by logging the time it takes to check a 404 or broken link.
Just the fact that the browser logs the time, shows that such scripts does not halt execution of javascript, the thread always continues on to the next script tag unless the parser encounters an error in a script, if the URL isn't found, no browser will throw an error, it just goes on as soon as the URL is not resolved.
<script>console.time('Test');</script>
<script type="text/javascript" src="http://www.broken.url/file.js"></script>
<script>console.timeEnd('Test');</script>
FIDDLE
Testing in IE, Chrome, Firefox and Opera shows that all browsers use less than 0.0002 seconds to resolve a broken link, and the time it takes to resolve a 404 depends on how fast the server responds, but for Google's servers it seems to consistently be less than 0.2 seconds in all browsers before the 404 status code is returned, and the browser keeps executing the next scripts.
Even adding up 20 scripts that all return a 404 takes generally less than half a second for the server to resolve and move on
FIDDLE
In other words, you can safely add any script that has a broken link or returns a 404, it won't break anything, and it won't hang the browser in any way, it only takes a few milliseconds for modern browser to determine that the script can't be loaded, and move on.
What you can't do, is include scripts that actually load, and contain fatal errors, as that will stop the entire thread, and any execution of scripts that comes after the error is encountered.
Define all functions you use (which are in //some_server/logger.js) as empty functions before loading the script and you'll have no exceptions even if you use them without the script being loaded.
<script type="text/javascript">
functionInLogger = function() {
};
functionInLogger2 = function() {
};
...
</script>
<script type="text/javascript" src="//some_server/logger.js"></script>
<script type="text/javascript">
functionInLogger();
functionInLogger2();
console.log("This will always work");
</script>
And when the script is loaded, it'll override the empty functions.
I could not find any popular browser that will stop execution upon a 404. And W3 standard only states this; (W3)
When the user agent is required to execute a script block, it must run the following 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.
You can place that script on the bottom of the page (after all your important script), to make sure this will not block rendering of your page.
Or you can also load it after document ready, this method will not give extra load time when the script are not found. Example:
$(document).ready(function() {
$('head').append('<script type="text/javascript" src="//some_server/logger.js"></script>');
});
or use $.getScript method
$(document).ready(function() {
$.getScript('//some_server/logger.js', function(data, textStatus) {
/*optional stuff to do after getScript */
});
});
* in example above I assume if you are using jQuery
I think you should use something like RequireJS.
From Wiki:
It allow developers to define dependencies that must load before a module is executed, so the module doesn't try to use outside code that isn't yet available.

how should my site handle ocassionally missing javascript files gracefully?

Say I've got this script tag on my site (borrowed from SO).
<script type="text/javascript" async=""
src="http://edge.quantserve.com/quant.js"></script>
If edge.quantserve.com goes down or stops responding without returning a 404, won't SO have to wait for the timeout before the rest of the page loads? I'm thinking Chaos Monkey shows up and blasts a server that my site is depending on, a server that isn't part of a CDN and has a poor failover.
What's the industry standard way to handle this issue? I couldn't find a dupe on SO, maybe I'm searching for the wrong terms.
Update: I should have looked a bit more closely at the SO code, there's this at the bottom:
<script type="text/javascript">var _gaq=_gaq||[];_gaq.push(['_setAccount','UA-5620270-1']);
_gaq.push(['_setCustomVar', 2, 'accountid', '14882',2]);
_gaq.push(['_trackPageview']);
var _qevents = _qevents || [];
(function(){
var s=document.getElementsByTagName('script')[0];
var ga=document.createElement('script');
ga.type='text/javascript';
ga.async=true;
ga.src='http://www.google-analytics.com/ga.js';
s.parentNode.insertBefore(ga,s);
var sc=document.createElement('script');
sc.type='text/javascript';
sc.async=true;
sc.src='http://edge.quantserve.com/quant.js';
s.parentNode.insertBefore(sc,s);
})();
</script>
OK, so if the quant.js file fails to load, it's creating a script tag with ga.async=true;. Maybe that's the trick.
Possible answer: https://stackoverflow.com/a/1834129/30946
Generally, it's tricky to do it well and cross-browser.
Some proposals:
Move the script to the very bottom of the HTML page (so that almost everything is displayed before you request that script)
Move it to the bottom and wrap it in <script>document.write("<scr"+"ipt src='http://example.org/script.js'></scr"+"ipt>")</script> or the way you added after update (document.createElement('script'))
A last option is to load it via XHR (but this works only for same-domain, or cross-domain only if the CORS is enabled on a third-party server); you can then use timeout property of the XHR (for IE and Fx12+), and in the other browsers, use setTimeout and check the XHR's readyState. It's kind of convoluted and very non-cross-browser for now, so the option 2 looks the best.
Make a copy of the file on your server and use this. it will load your copy only if the one from the server has failed to load
<script src="http://edge.quantserve.com/quant.js"></script>
<script>window.quant || document.write('<script src="js/quant.js"><\/script>')</script>
To answer your question about the browser having to wait for the script to load before the rest of the page loads, the answer to that would typically be no. Typical browsers will have multiple threads processing the download of the page and linked content (CSS, images, js). So the rest of the page should be loaded, though the user's browser indicator will still show the page trying to load until the final request is fulfilled or timed out.
Depending on the nature of the resource you are trying to load, this will obviously effect your page differently. Typically, if you are worried about this, you can host all your files on a common CDN (or your website if it is not that highly trafficked), that way at least if one thing fails, chances are everything is failing and you have a bigger issue to contend with :)

AddThis and Google Page Speed

No matter how I try to load AddThis (using Google +1, Facebook Send and Like, and Twitter buttons as default), Google Page Speed still warns about:
Leverage browser caching
Defer parsing of Javascript
In each of these items, .html and .js references to AddThis, Facebook, Google +1, Twitter, and static.ak.fbcdn.net are referenced. In fact, if you run Google Page Speed on this page: http://support.addthis.com/customer/portal/articles/381263-addthis-client-api-#rendering-js, you will see exactly what I'm talking about. The first two items, both with orange severity icons (at least for me), are exactly what I mentioned above.
I've tried adding the script tag to the head of my page using defer (for IE) and async (for FF and Chrome) with no luck:
<script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid=myUserId" defer="defer" async="async"></script>
I've tried using $.getScript():
$(document).ready(function () {
$.getScript('http://s7.addthis.com/js/250/addthis_widget.js#async=1#username=myUserId', function(data, textStatus) {
addthis.init();
});
});
And I also tried turning the ajax cache on:
$(document).ready(function () {
$.ajaxSetup({ cache: true });
$.getScript('http://s7.addthis.com/js/250/addthis_widget.js#async=1#username=myUserId', function(data, textStatus) {
addthis.init();
$.ajaxSetup({ cache: false });
});
});
Is there any way I can cache, and also defer the loading of AddThis and it's external references?
Leverage browser caching
Well this is just a proposal to set more time cache of some pages. On my pages I get this two warning - both from google script :). Is not so important because this javascript all ready have a good time cache for javascript.
http://pagead2.googlesyndication.com/pagead/show_ads.js (60 minutes)
http://www.google-analytics.com/ga.js (2 hours)
Defer parsing of Javascript
Well, this is an automatic program that try to understand if the page is slow and suggest some thinks to improve it. At this point is not accurate.
I just run it on known page that work find and full of cache and other tricks, and get the same messages.
Is like just a suggestion and not actually can know if this javascript really do all ready what he say - at least for the moment. For example in my test page I load a javascript at the end of the page and I get this message again. If you know that you load the javascript at the correct timing with the correct flags, do not worry about this messaage.
Check the report for this page :
https://developers.google.com/pagespeed/#url=http_3A_2F_2Fstackoverflow.com_2Fquestions_2F9739031_2Faddthis-and-google-page-speed&mobile=false&rule=LeverageBrowserCaching
<script type="text/javascript"charset="utf-8" src="/js/addthis.js#async=1"</script>
This has been resolved in our site. http://www.nbhuntop.com
You may try copy the addthis code first. and quote as src="/js/addthis.js#async=1"

Find Missing Javascript Includes in Website

Say I have several JavaScript includes in a page:
<script type="text/javascript" src="/js/script0.js"></script>
<script type="text/javascript" src="/js/script1.js"></script>
<script type="text/javascript" src="/js/script2.js"></script>
<script type="text/javascript" src="/js/script3.js"></script>
<script type="text/javascript" src="/js/script4.js"></script>
Is there a way i can tell if any of those weren't found (404) without having to manually check each one? I guess i'm looking for an online tool or something similar. Any ideas?
If you get the Firebug firefox plugin and enable the consoles it should tell you when there are errors retrieving resources in the console.
I don't use other browsers enough to know where to find a similar feature in them, but Safari has an Activity window that displays all of the included files for a given web page and which ones were unable to be retrieved.
If you want to monitor on the fly without actually checking if it exists, then I suggest placing dynamic variables inside the files. Then just do something like this:
var script0Exists = true; // inside script0.js
var script1Exists = true; // inside script1.js
Then in your other files, just use:
if ( script0Exists ) {
// not a 404 - it exists
}
Log your 404's.
If you don't want to check it manually on the client you will need to do this server-side. You need to make sure whichever webserver you are using is configured to log 404s and then check that log to see which HTTP requests have failed.
If your webhost always returns the HTTP result "200 OK", whether the file exists or not (the latter should give a "404 Not Found"), the browser has no way of telling if it received a script or not.
You might try retrieving the files via XMLHttpRequest, examine the data, and if they look like JS, either eval() them, or create a script tag pointing to the exact same URL you downloaded (if the script is cacheable, it won't be transferred again, as the browser already has it).

Categories