How do you detach your pageload from third party scripts? - javascript

I have this problem where the UI components of my page like the drop down menus arent available until thirdparty scripts finish loading. This causes a problem because who knows whats going on on those servers. I need to detach the availability of the page's interactive components from the loading of thirdparty stuff...
how?
=/

Try something like this:
<script type="text/javascript">
window.onload = function() {
var scripts = [ '3rdparty1url','3rdparty2url','3rdparty3url',etc...];
var head = document.getElementsByTagName('head')[0];
for(var i = 0; i < scripts.length; ++i) {
var scriptTag = document.createElement('script');
scriptTag.src = scripts[i];
head.appendChild(scriptTag);
}
}
</script>
This will load in your external script files after the page has finished loading in the client's browser. Your form UI elements should all be available.
If you're using jQuery, you can do this:
<script type="text/javascript">
jQuery(function($){
var scripts = [ '3rdparty1url','3rdparty2url','3rdparty3url',etc...];
$.each(scripts, function(i,scrurl) {
$('head').append($('<script>', { src: scrurl }));
}
});
</script>

You should carefully think your page so that it is nicely degradable.
Make the menu available in some "bare" form before the JS are loaded and once they are you can then change the UI to be superfancy and full of bells and whistles :)
That will also be useful for those users (probably not many, but still...) who have JS turned off, and for indexing spiders to catch the content of your menus.

JS performance guru Steve Souders on JavaScript blocking and asynchronous loading gives a good overview. Google "asynchronous javascript loading" for a lot more information. There are libraries that can schedule and load external files too. Another.

Related

Site content shifts vertically on certain pages

I'm in the process of building a new website for my wife's business, using Squarespace. Don't tell her, since it's one of her Christmas presents. :)
However, I'm experiencing a weird issue. About half of the pages on the site include content from a third-party widget called Healcode. Those pages have a strange jerkiness to them on pageload, where the logo and navbar move around -- ultimately winding up in the right spot, but looking bad while doing so. Pages that don't have a third-party widget don't have this jerkiness.
Example of page that jerks: https://coconditioning.squarespace.com/yoga-classes/
Example of page that doesn't jerk: https://coconditioning.squarespace.com/private-coaching/
The Healcode widget is javascript code that looks like this:
<script type="text/javascript">
healcode_widget_id = "ay12237c4nc";
healcode_widget_name = "schedules";
healcode_widget_type = "mb";
document.write(unescape("%3Cscript src='https://www.healcode.com/javascripts/hc_widget.js' type='text/javascript'%3E%3C/script%3E"));
// Healcode Schedule Widget for Conscious Conditioning L.L.C. : Weekly Schedule New
</script>
<noscript>Please enable Javascript in order to get HealCode functionality</noscript>
Any help would be MUCH appreciated. Thank you in advance!
You could hide the page until the body loads:
<body style = 'display: none'; />
And in your javascript, adding window.onload():
healcode_widget_id = "ay12237c4nc";
healcode_widget_name = "schedules";
healcode_widget_type = "mb";
document.write( unescape("%3Cscript src='https://www.healcode.com/javascripts/hc_widget.js' type='text/javascript'%3E%3C/script%3E"));
// Healcode Schedule Widget for Conscious Conditioning L.L.C. : Weekly Schedule New
window.onload = function()
{
document.body.style.display = 'block';
};
Also, is document.write() the best solution for you?
Don't try to use document.write if possible as with document.write JS parser doesn't know where to put it. at best, the browser will ignore it. at worst, it could write over the top of your current document. Use appendChild
function loadHealCodeScript () {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://www.healcode.com/javascripts/hc_widget.js'
document.body.appendChild(script);
}
window.onload = loadHealCodeScript; // load healcode after page has been loaded
The jittering effect is happening because the healcode is loading its script before the page has completely loaded. If possible place all you javascripts after the body tag rather than head
As suggested by google also https://developers.google.com/maps/documentation/javascript/tutorial?hl=en#asynch

Detect whether external script has loaded

Using JavaScript, is there a way to detect whether or not an external script (from a third-party vendor) has completely loaded?
The script in question is used to pull in and embed the markup for a list of jobs and, unfortunately, doesn't make use of any variables or functions. It uses document.write to output all of the content that gets embedded in my page.
Ideally, I'd like to display some kind of loading message while I'm waiting for the external script to load, and if it fails to load, display a "We're sorry, check back later..." message.
I'm using jQuery on the site, but this external script is called before I make the jQuery call.
Here's what the document.write stuff from the external script looks like:
document.write('<div class="jt_job_list">');
document.write("
<div class=\"jt_job jt_row2\">
<div class=\"jt_job_position\">
Position Title
</div>
<div class=\"jt_job_location\">City, State</div>
<div class=\"jt_job_company\">Job Company Name</div>
</div>
");
Attach an function to the load event:
<script type="text/javascript" src="whatever.js" onload ="SomeFunction()" />
As far as your loading... problem goes, try displaying a div for loading and then just display:none-ing it in your onload function. Make sure to handle cases where your script fails to load too, though.
Script tags block downloads, so as long as the content dependent on your script is below where your script it loaded, you should be fine. This is true even if the script is in-line in the body of your page.
This website has a great example of how this works.
This obviously does not work if you're loading the scripts asynchronously.
Scripts without async or defer attributes are fetched and executed immediately, before the browser continues to parse the page.
Source: MDN
You could put a script block after it on the page:
<script src="external_script.js"></script>
<script type="text/javascript">
ExternalScriptHasLoaded();
</script>
Thanks for the assistance above, especially ngmiceli for the Steve Souders link!
I decided to take what's probably a "lazy" approach, and also forego the "loading" message:
$(document).ready(function(){
if ($('.jt_job_list').length === 0){
$('#job-board').html("<p>We're sorry, but the Job Board isn't currently available. Please try again in a few minutes.</p>");
};
});
Pretty simple, but I'm looking to see if an element with the .jt_job_list class is in the dom. If it isn't, I display an error message.
This worked for me: it does however, rely on the newer querySelector interface which most modern browsers support. But if you're using really old browsers, you can use getElement... and run a for loop.
function loadJS(file, callback, error, type) {
var _file = file ;
var loaded = document.querySelector('script[src="'+file+'"]') ;
if (loaded) {
loaded.onload = callback ;
loaded.onreadystatechange = callback;
return
}
var script = document.createElement("script");
script.type = (typeof type ==="string" ? type : "application/javascript") ;
script.src = file;
script.async = false ;
script.defer = false ;
script.onload = callback ;
if (error) {
script.onerror = error ;
}
else {
script.onerror = function(e) {
console.error("Script File '" + _file + "' not found :-(");
};
}
script.onreadystatechange = callback;
document.body.appendChild(script);
}
You could give what ever your looking for an ID
and check whether not the ID has been loaded using document.getElementById("ID");
Is that what your looking for not sure I fully understand?

slow / unresponsive / stuck typekit script

ive installed typekit on my site, the usual two lines of js just after the opening head tag but its extremely slow / unresponsive to load in the fonts, this is completly remedied by refreshing the page, after that the typekit font load in perfectly and really quickly. But from a users point of view they will never know to do that, so they will be served the default fonts.
I have the typekit js as the very first thing under the opening head tag before the metatags and before loading in jquery, jquery-ui and other scripts.
Has any one else had trouble with this ?
what seemed to work for me was to load the script in an asynchronous pattern - as specified on the typekit blog, ive copied it in bellow
Standard asynchronous pattern
This first pattern is the most basic. It’s based on patterns written about by web performance experts like Steve Souders and used in other JavaScript embed codes like Google Analytics.
<script type="text/javascript">
TypekitConfig = {
kitId: 'abc1def'
};
(function() {
var tk = document.createElement('script');
tk.src = '//use.typekit.com/' + TypekitConfig.kitId + '.js';
tk.type = 'text/javascript';
tk.async = 'true';
tk.onload = tk.onreadystatechange = function() {
var rs = this.readyState;
if (rs && rs != 'complete' && rs != 'loaded') return;
try { Typekit.load(TypekitConfig); } catch (e) {}
};
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(tk, s);
})();
</script>
This pattern uses a single inline tag to dynamically add a new script element to the page, which loads the kit without blocking further rendering. An event listener is attached that calls Typekit.load() once the script has finished loading.
How to use it:
Place this snippet at the top of the so the download starts as soon as possible.
Edit the highlighted TypekitConfig object and replace the default with your own Kit ID.
You can add JavaScript font event callbacks to the TypekitConfig object.
Advantages:
Loads the kit asynchronously (doesn’t block further page rendering while it loads).
Disadvantages:
Adds more bytes to your html page than the standard Typekit embed code.
Causes an initial FOUT in all browsers that can’t be controlled or hidden with font events.

How to load Google's Custom-search-engine(CSE) JS APIs after page loads?

I am using Google Custom Search Engine with their new auto-completion feature. I want this whole javascript to be loaded AFTER the page itself is loaded. The original Google code is this:
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load('search', '1');
google.setOnLoadCallback(function() {
google.search.CustomSearchControl.attachAutoCompletion(
'some-long-unique-id',
document.getElementById('q'),
'cse-search-box');
});
</script>
<script type="text/javascript" src="http://www.google.com/cse/brand?form=cse-search-box&lang=cs"></script>
I have transformed this code using tutorial about JS dynamic loading to this code:
(function() {
var goog = document.createElement('script'); goog.type = 'text/javascript';
goog.src = 'http://www.google.com/jsapi';
var cse = document.createElement('script'); cse.type = 'text/javascript';
cse.src = 'http://www.google.com/cse/brand?form=cse-search-box&lang=cs';
goog.onload = function() {
google.load('search', '1');
google.setOnLoadCallback(function() {
google.search.CustomSearchControl.attachAutoCompletion(
'some-long-unique-id',
document.getElementById('q'),
'cse-search-box');
});
};
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(cse, s);
s.parentNode.insertBefore(goog, s);
})();
Well, even though I think my solution should work(the same way has Google changed their Analytics on-demand asynchronous code), it doesn't. The page loads fine and as soon as CSE loads, the page goes blank. Something clears the DOM, I suppose its some kind of "Google thing" ? Can someone bring some light on this problem and possibly a working solution ?
Thanks
OK, so by checking Google Loader Developer's Guide and by lots of trying-and-testing I've figured how to change my code so it works as I expected in my question:
(function() {
var goog = document.createElement('script'); goog.type = 'text/javascript';
goog.src = 'http://www.google.com/jsapi';
goog.onload = function() {
google.load('search', '1', {"callback": function() {}});
google.setOnLoadCallback(function() {
google.search.CustomSearchControl.attachAutoCompletion(
'some-long-unique-id',
document.getElementById('q'),
'cse-search-box');
});
};
var cse = document.createElement('script'); cse.type = 'text/javascript';
cse.src = 'http://www.google.com/cse/brand?form=cse-search-box&lang=cs';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(cse, s);
s.parentNode.insertBefore(goog, s);
})()
The main thing is this line:
google.load('search', '1', {"callback": function() {}});
If you don't specify callback (at least empty function as I do), then the whole page goes blank, when Google's CSE loads. I have no idea why, but it works fine now with this dummy callback function.
Hope it helps someone with the same problem.
I guess you can use some js loader (eg yepnope) that allows you to load js on demand and add a callback.
I don't fully-understand what you're trying to achieve. You've asked for someone to suggest how to 'correct' your code, but you haven't given any context, or what you actually want the end-result to be.
Also, the updates you've provided with the function()s you've written- it's not clear how these are being called. In the when the document readyState is complete?
Firstly, I'd suggest using jQuery to wrap up the JavaScript stuff. Yes, Google provide onload events and other helpers for their API, but jQuery will apply to any Javscript, there's no point in using two Javascript frameworks where you don't have to.
The jQuery might be like this:
<script type="text/javascript" language="javascript" src="/js/jquery/jquery-1.4.2.min.js"></script>
<script type="text/javascript" language="javascript">
// Use the jQuery document load functionality.
$(document).ready(function ()
{
// Load the Google API asynchronously. The callback 'GoogleApiLoaded' will be called when the script is fully-loaded.
$.getScript("http://www.google.com/jsapi?key=yourkey", GoogleApiLoaded);
// Load other scripts, do other init code here (non-Google-dependent).
});
function GoogleApiLoaded()
{
// Google-related init here.
// Load the custom search API.
// (Could make the callback an in-line function).
$.getScript("http://www.google.com/cse/brand?form=cse-search-box&lang=cs", CustomSearchApiLoaded);
}
function CustomSearchApiLoaded()
{
google.load('search', '1', LoadCustomSearchControl);
}
function LoadCustomSearchControl()
{
google.search.CustomSearchControl.attachAutoCompletion('some-long-unique-id', document.getElementById('q'), 'cse-search-box');
}
</script>
It might be helpful to break the code apart into different functions, in order to track-down more easily where the problem is. That you have to put in an optional callback on the 'google.load()' function is strange- it may be a bug in the Google code, there are some floating around.
I've used google.load('search', '1', LoadCustomSearchControl), rather than the google.setOnLoadCallback, because as far as I can see they should do the same thing, and using a callback on load() is neater, in my view.
I'd strongly advise you use jQuery (or any JavaScript framework), as it makes life a lot easier.
I'd be interested to see whether what I've suggested works, and if not where it goes wrong. (Make sure to add-in your own JSAPI key).

What are the ways to minimize page wait from external javascript callouts?

What tricks can be used to stop javascript callouts to various online services from slowing down page loading?
The obvious solution is to do all the javascript calls at the bottom of the page, but some calls need to happen at the top and in the middle. Another idea that comes to mind is using iframes.
Have you ever had to untangle a site full of externally loading javascript that is so slow that it does not release apache and causes outages on high load? Any tips and tricks?
window onload is a good concept, but the better option is to use jQuery and put your code in a 'document ready' block. This has the same effect, but you don't have to worry about the onload function already having a subscriber.
http://docs.jquery.com/Core/jQuery#callback
$(function(){
// Document is ready
});
OR:
jQuery(function($) {
// Your code using failsafe $ alias here...
});
edit:
Use this pattern to call all your external services. Refactor your external script files to put their ajax calls to external services inside one of these document ready blocks instead of executing inline. Then the only load time will be the time it takes to actually download the script files.
edit2:
You can load scripts after the page has loaded or at any other dom event on the page using built in capability for jQuery.
http://docs.jquery.com/Ajax/jQuery.getScript
jQuery(function($) {
$.getScript("http://www.yourdomain.com/scripts/somescript1.js");
$.getScript("http://www.yourdomain.com/scripts/somescript2.js");
});
Not easy solution. In some cases it is possible to merge the external files into a single unit and compress it in order to minimize HTTP requests and data transfer. But with this approach you need to serve the new javascript file from your host, and that's not always possible.
I can't see iframes solving the problem... Could you please elaborate ?
See articles Serving JavaScript Fast and Faster AJAX Web Services through multiple subdomain calls for a few suggestions.
If you're using a third-party JavaScript framework/toolkit/library, it probably provides a function/method that allows you to execute code once the DOM has fully loaded. The Dojo Toolkit, for example, provides dojo.addOnLoad. Similarly, jQuery provides Events/ready (or its shorthand form, accessible by passing a function directly to the jQuery object).
If you're sticking with plain JavaScript, then the trick is to use the window.onload event handler. While this will ultimately accomplish the same thing, window.onload executes after the page--and everything on it, including images--is completely loaded, whereas the aforementioned libraries detect the first moment the DOM is ready, before images are loaded.
If you need access to the DOM from a script in the head, this would be the preferred alternative to adding scripts to the end of the document, as well.
For example (using window.onload):
<html>
<head>
<title>Test Page</title>
<script type="text/javascript">
window.onload = function () {
alert(document.getElementsByTagName("body")[0].className);
};
</script>
<style type="text/css">
.testClass { color: green; background-color: red; }
</style>
</head>
<body class="testClass">
<p>Test Content</p>
</body>
</html>
This would enable you to schedule a certain action to take place once the page has finished loading. To see this effect in action, compare the above script with the following, which blocks the page from loading until you dismiss the modal alert box:
<html>
<head>
<title>Test Page</title>
<script type="text/javascript">
alert("Are you seeing a blank page underneath this alert?");
</script>
<style type="text/css">
.testClass { color: green; background-color: red; }
</style>
</head>
<body class="testClass">
<p>Test Content</p>
</body>
</html>
If you've already defined window.onload, or if you're worried you might redefine it and break third party scripts, use this method to append to--rather than redefine--window.onload. (This is a slightly modified version of Simon Willison's addLoadEvent function.)
if (!window.addOnLoad)
{
window.addOnLoad = function (f) {
var o = window.onload;
window.onload = function () {
if (typeof o == "function") o();
f();
}
};
}
The script from the first example, modified to make use of this method:
window.addOnLoad(function () {
alert(document.getElementsByTagName("body")[0].className);
});
Modified to make use of Dojo:
dojo.addOnLoad(function () {
alert(document.getElementsByTagName("body")[0].className);
});
Modified to make use of jQuery:
$(function () {
alert(document.getElementsByTagName("body")[0].className);
});
So, now that you can execute code on page load, you're probably going to want to dynamically load external scripts. Just like the above section, most major frameworks/toolkits/libraries provide a method of doing this.
Or, you can roll your own:
if (!window.addScript)
{
window.addScript = function (src, callback) {
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.src = src;
script.type = "text/javascript";
head.appendChild(script);
if (typeof callback == "function") callback();
};
}
window.addOnLoad(function () {
window.addScript("example.js");
});
With Dojo (dojo.io.script.attach):
dojo.addOnLoad(function () {
dojo.require("dojo.io.script");
dojo.io.script.attach("exampleJsId", "example.js");
});
With jQuery (jQuery.getScript):
$(function () {
$.getScript("example.js");
});
If you don't need a particular script ad load time, you can load it later by adding another script element to your page at run time.

Categories

Resources