To avoid the Google Pagespeed Messeger "Parsing Javascript later" I've copied this script.
<script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "http://example.com/templates/name/javascript/jquery.js";
document.body.appendChild(element);
var element1 = document.createElement("script");
element1.src = "http://example.com/templates/name/javascript/jquery.colorbox-min.js";
document.body.appendChild(element1);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else
window.onload = downloadJSAtOnload;
</script>
How could I solve it with a loop because I need one more javascript file insert into the DOM.
Greets
Ron
You can make a function like this that takes an arbitrary number of script filenames:
function loadScriptFiles(/* pass any number of .js filenames here as arguments */) {
var element;
var head = document.getElementsByTagName("head")[0];
for (var i = 0; i < arguments.length; i++) {
element = document.createElement("script");
element.type = "text/javascript";
element.src = arguments[i];
head.appendChild(element);
}
}
function downloadJSAtOnload() {
loadScriptFiles(
"http://example.com/templates/name/javascript/jquery.js",
"http://example.com/templates/name/javascript/jquery.colorbox-min.js",
"http://example.com/templates/name/javascript/myJS.js"
);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else
window.onload = downloadJSAtOnload;
If your script files have a required load order (I presume colorbox must load after jQuery, for example), you will have to do something more sophisticated than this because this loads them all asynchronously so they have no guaranteed load order. Once you need a particular load order, it's probably best to get code that someone else has written to solve this problem like RequireJS or LABjs or Google.load().
Note: I'm also appending the script files to the <head> tag which is a bit better place to put them.
When using LABjs, you are not putting the .wait() in the right place. .wait() tells the loader to wait until all PRIOR scripts are loaded before loading the next one. I think you need it like this:
$LAB
.script("templates/name/javascript/jquery.js").wait()
.script("templates/name/javascript/jquery.colorbox-min.js");
Related
I want to defer the loading of a particular Javascript file. On GTMetrix, I get a 14 score under the 'Defer Loading Of Javascript' category. I want to defer the loading of this file:
https://www.youtube.com/yts/jsbin/player_ias-vflRCamp0/en_US/base.js
I've tried inserting scripts in my Theme's Footer, right before the tag. Here's what I've tried:
`<script type="text/javascript">
function parseJSAtOnload() {
var element = document.createElement("script");
element.src = "https://www.youtube.com/yts/jsbin/player_ias-vflRCamp0/en_US/base.js";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", parseJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", parseJSAtOnload);
else window.onload = parseJSAtOnload;
</script>
`
I've also tried:
`<script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "https://www.youtube.com/yts/jsbin/player_ias-vflRCamp0/en_US/base.js";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
</script>`
These scripts do nothing to the GTMetrix score.
I've tried this as well:
`<script type="text/javascript">
function parseJSAtOnload() {
var links = ["www.youtube.com/yts/jsbin/player_ias-vflRCamp0/en_US/base.js", "www.youtube.com/yts/jsbin/www-embed-player-vflO7uv3_/www-embed-player.js"],
headElement = document.getElementsByTagName("head")[0],
linkElement, i;
for (i = 0; i < links.length; i++) {
linkElement = document.createElement("script");
linkElement.src = links[i];
headElement.appendChild(linkElement);
}
}
if (window.addEventListener)
window.addEventListener("load", parseJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", parseJSAtOnload);
else window.onload = parseJSAtOnload;
</script>`
This script will work temporarily. I'll test the page on GTMetrix and it shows that the Javascript is deferred. On the Waterfall chart, it shows that those scripts are canceled (insight here would be appreciated as well?)
When I Retest to make sure it's working, I'm back to the original score of 14. What else can I try, or what am I doing wrong?
Website Here: https://www.fralinpickups.com/product/vintage-hot/
You should create a file with your code and queue it with [wp_enqueue_script][1] hook.
If your file is called my_script.js and it is in the folder /js/ of your theme, the function should look like this:
// You probably already have a function to enqueue scripts in your theme function.php file.
function my_script() {
wp_enqueue_script( 'my_script', get_template_directory_uri() . '/js/my_script.js', array(), '1.0.0', true );
}
add_action( 'wp_enqueue_scripts', 'my_script' );
The key to load it after other scripts is in the fifth parameter of the function, when set to true it loads the script in the footer, before the body tag. If your script requires jQuery and/or other dependencies you can add them in the array using the corresponding handle, as indicated in the documentation (here).
If you want to asign defer to the script tag you could use the following:
function add_defer_attribute($tag, $handle) {
if ( 'my_script' !== $handle )
return $tag;
return str_replace( ' src', 'defer="defer" src', $tag );
}
add_filter('script_loader_tag', 'add_defer_attribute', 10, 2);
More info on script_loader_tag.
Update:
Here is a valid answer that can help you with deferring youtube javascript: How do you Defer Parsing of JavaScript for YouTube video on a WordPress site?
A hypothetical third-party JS vendor provides this script to include in every page:
(function() {
function loadAsync(){
// Inject the script.
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://example.com/3rdPartyStuff.js';
// Find a reasonable place to inject the script.
var firstScript = document.getElementsByTagName('script')[0];
firstScript.parentNode.insertBefore(script, firstScript);
}
// Attach the script loader to the load event.
if (window.attachEvent) {
window.attachEvent('onload', loadAsync);
} else {
window.addEventListener('load', loadAsync, false);
}
})();
Do other load event handlers have to wait for this script to download and execute before continuing, or can other JS run until this script is available and ready to execute?
Does the answer to this question vary by browser?
As Pointy and Patrick explained in the comments, the load event fully plays out before any injected scripts execute. I wrote up a demo which confirms this in Chrome, IE, and Edge (I stopped testing after those).
Test it on JSFiddle: https://jsfiddle.net/bhh7szyh/3/
In short, I don't have to worry about the third party script slowing down the load event.
Patrick also described the behavior of scripts added with the async attribute:
The default behavior of dynamically injected scripts is to load asynchronously if async is not set, but setting it to false will cause modern browsers to execute it synchronously.
Test code:
<!DOCTYPE html>
<html>
<head>
<title>Tests</title>
<script>
(function() {
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
function loadAsync(url){
// Inject the script.
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
// Find a reasonable place to inject the script.
var firstScript = document.getElementsByTagName('script')[0];
firstScript.parentNode.insertBefore(script, firstScript);
}
function attach_to_load(fn) {
if (window.attachEvent) {
window.attachEvent('onload', fn);
} else {
window.addEventListener('load', fn, false);
}
}
attach_to_load(function() { sleep(5000); console.log('before injected JS'); });
attach_to_load(function() { loadAsync('https://pastebin.com/raw/g40BS6Tg') });
attach_to_load(function() { sleep(5000); console.log('after injected JS'); });
})();
</script>
</head>
<body>
<h1>Tests Happened</h1>
</body>
</html>
To speed up the page loading time, I want to load the JS scripts after the page content has loaded.
I found this helpful article which explains how to do this when you have a single JS file: https://varvy.com/pagespeed/defer-loading-javascript.html
The solution goes like this:
<script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "yourSingleJSFile.js";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
</script>
In my case, I have 4 different js files: jQuery, main.js and index.js that are starting with $(document).ready(...); and define a function initMap(), and maps.googleapis.com. Therefore I changed the code to
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js";
document.body.appendChild(element);
var element = document.createElement("script");
element.src = "/resources/js/main.js";
document.body.appendChild(element);
var element = document.createElement("script");
element.src = "/resources/js/index.js";
document.body.appendChild(element);
var element = document.createElement("script");
element.src = "https://maps.googleapis.com/maps/api/js?key=***mysecetrkey**&callback=initMap";
document.body.appendChild(element);
Each time I load the page, I find a JS error in the console. There are two errors that I spotted so far:
First
ReferenceError: $ is not defined index.js:9:5
I don't understand what is happening here. It seems like index.js was included before jquery was loaded. But how come the error is not thrown in main.js?
Second
validValueError: initMap is not a function
It seems to me that googleapis.com js is already loaded but index.js is missing (since I define function initMap() there).
How can I force the scripts to load sequently after the page content has loaded?
If the scripts have dependencies towards each other you need to make sure that the dependencies loads first. You can nest the script loading like so:
var jqueryElement = document.createElement("script");
jqueryElement.src = "https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js";
var mainElement = document.createElement("script");
mainElement.src = "/resources/js/main.js";
var indexElement = document.createElement("script");
indexElement.src = "/resources/js/index.js";
var googleApiElement = document.createElement("script");
googleApiElement.src = "https://maps.googleapis.com/maps/api/js?key=***mysecetrkey**&callback=initMap";
// add the first script element
document.body.appendChild(jqueryElement);
jqueryElementElement.onload = function () {
document.body.appendChild(googleApiElement);
}
googleApiElement.onload = function () {
document.body.appendChild(mainElement);
document.body.appendChild(indexElement)
}
I'm just guessing your dependency order.
I'm optimizing my site based on Google's PageSpeed Insights. It recommends that I "Remove Render-Blocking JavaScript" for several files (names simplified for example's sake):
<script src="js/1.js" type="text/javascript"></script>
<script src="js/2.js" type="text/javascript"></script>
<script src="js/3.js" type="text/javascript"></script>
I'm trying Patrick Sexton's "Defer Loading Javascript" approach which only defers one file (defer.js):
<script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "defer.js";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
</script>
My question is, how can this approach be modified to include multiple files (i.e. 1.js, 2.js, 3.js)?
you can use HeadJS
for this. I was using it for one of our projects and it was pretty useful.
<script type="text/javascript">
function downloadJSAtOnload() {
var links = ["js/1.js", "js/2.js", "js/3.js"],
headElement = document.getElementsByTagName("head")[0],
linkElement, i;
for (i = 0; i < links.length; i++) {
linkElement = document.createElement("script");
linkElement.src = links[i];
headElement.appendChild(linkElement);
}
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
</script>
Google Pagespeed told me to load my JS files asynchronously, so I wrote this code:
// Add script elements as a children of the body
function downloadJSAtOnload() {
var filesToLoad = [
["/assets/plugins/typeahead.bundle.min.js", "onTypeaheadLoaded"],
["https://apis.google.com/js/client:plusone.js?onload=googlePlusOnloadCallback", ""]
];
filesToLoad.forEach(function(entry) {
var element = document.createElement("script");
element.src = entry[0];
if (entry[1] != "") { // if an onload callback is present (NOTE: DOES NOT SUPPORT NAMESPACES -- http://stackoverflow.com/a/359910/1101095)
element.onload = function() {
if (typeof window[entry[1]] != "undefined") {
window[entry[1]]();
}
};
}
document.body.appendChild(element);
});
}
// Check for browser support of event handling capability
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
However, someone just directed me to this article, which says using the async attribute is better than injecting script tags (this is contrary to what I've read most places, but the author show evidence he's right).
So, my question is, if I change to using the async attribute, is there a way to have a function triggered when the script is done loading?