Onesignal Plugin Defer JS - javascript

Hi there I have a wordpress site with and I have defered scripts setup per the GT Metrix recommendations. All scripts are defered except for Onesignal Push Notification plugin,
<script src="https://cdn.onesignal.com/sdks/OneSignalSDK.js" async></script>
function js_defer_attr($tag){
$scripts_to_exclude = array('.jsdelivr');
foreach($scripts_to_exclude as $exclude_script){
if(true == strpos($tag, $exclude_script ) )
return $tag;
}
return str_replace( ' src', ' defer="defer" onload src', $tag );
}
add_filter( 'script_loader_tag', 'js_defer_attr', 10 );
I am guessing it is adding script loading after page load/defering has been done?
Any help?
Cheers

I did it on my websites and it is working fine... and more important page stuff will load first. The user experience is better this way.
I will explain what I did.
I changed the OneSignal plugin code and moved to another file all that code it ads to the header. A file is created at runtime when it does not exists.
Let's suppose I create a new file called "onesignal_deferred.js".
Then I added to the footer of the page:
function add_script(url){
var element = document.createElement("script");
element.src = url;
document.body.appendChild(element);
}
function downloadJSAtOnload(){
add_script("add_script("https://<domain>/onesignal_deferred.js")
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
The manifest is not necessary as well... as it is suited for older versions of Chrome... so it is a new optimization you can do to save one more request per page view.
I can also use this same function "add_script" to defer other scripts like Google Analytics and any other.
p.s.: when you defer Google Analytics, sometimes it will not count as a view a page that is closed before the Load Event... in this case you might be tricked by a false Google Analytics report saying that pages as loading faster. The case is that too slow loading pages will not be counted on...as Google Analytic script will not even be loaded.

Related

Removing render-blocking JavaScript for Jquery UI Library

I am attempting to try speed up my web page by "Removing render-blocking JavaScript" using this defer method:
<script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "js/combination.js"; // replace defer.js with your script instead
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>
I've combined all my javascript files into 1 called combinations.js but whenever I try combine this jquery library UI:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
with combinations.js, my jquery scripts don't work.
So Google Page speed is still saying that I need "Removing render-blocking JavaScript" for this library but how?
UPDATE:
When I add the Jquery UI Library to the top of my combination.js file and test it on CHROME and IE9 it works! The problem I now have above, is when I test it on Firefox (I've got version 35). So this seems to be a firefox issue
It looks like It was my history in firefox not re-loading my Jquery Library even when I did a full refresh (CRTL + F5). Strange, anyway if anyone happens to get this problem, delete all your history and load up your website up again. Amazing how such a simple solution can take up so much time.

Javascript Deferred Functions

I've been looking around at JavaScript to try and get some code to load asynchronously
I found this code sample
<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>
from http://www.feedthebot.com/pagespeed/defer-loading-javascript.html
The thing is it doesn't quite do what I'm trying to achieve. I would like to be able to do something similar but setup a deferred or some type of function that is called after this has all loaded. Is that possible? If so can anyone help explain how?
You can try to use the onload event of the script tags you are loading. See this question, for example: Trying to fire the onload event on script tag. However, this mechanism seems pretty sketchy and may not be cross-browser.
Another possible approach is to have the script that is being loaded trigger an event that can be handled by the existing javascript on the page. This may or may not make sense for your particular case, and it requires you to have control over the loaded script.
Finally, these days it's rare for javascript loading to be a performance bottleneck for your website. So why are you trying to dynamically load javascript? Could you solve the same problem by loading some other resource, e.g. by doing an AJAX request?
You've tagged jQuery on your question. It has $.getScript() which does exactly what you're asking for in a purely cross browser fashion. It will load the script asynchronously and then call the specified callback when the script has finished loading and initializing:
$.getScript("defer.js", function() {
// script loaded here
// you can run code here that uses that script
});
If you really want to wait until the DOM is loaded before loading this script (generally not necessary), you could do this:
$(document).ready(function() {
$.getScript("defer.js", function() {
// script loaded here
// you can run code here that uses that script
});
});
Or, to wait until ALL other resources are loaded including images:
$(window).load(function() {
$.getScript("defer.js", function() {
// script loaded here
// you can run code here that uses that script
});
});
If you're interested in some references on when scripts are loaded (particularly with defer and async attributes, you can read this detailed post.

Can Bootstrap be loaded asynchronously?

I have not used Bootstrap for very long and am unsure of whether it needs to be loaded non-asynchronously in the <head> for page-building purposes.
Google suggests using this code to load JS files asynchronously:
<script type="text/javascript">
// Add a script element as a child of the body
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "deferredfunctions.js";
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;
</script>
Can I load bootstrap.min.js in this fashion, or should I load it non-asynchronously?
Bootstrap.js requires jquery to run. If you are looking to get the benefit of loading async script, then you would probably want to load jquery (and potentially other libraries) async as well... The problem with this is that you would have no guarantee that jquery async finished before the bootstrap using the example code above. I'm also sure you have your own javascript that you want to write to use the bootstrap.js features. This means even more dependencies. You could write logic to wire up dependencies and async load manually, but this would become a lot of work as the number of scripts you might need to include increase.
Requirejs is a library that takes care of all this dependency management for you, and can load your files asynchronously (and in the correct order). Another benefit of this library is the optimizer which can trace dependencies and "burn" them into a single (optionally minified) file. After you use the optimizer to optimize your "main" js file (the one with all the dependencies you need for the page), requireJS can just load that file asynchronously. Only need one script include!
An example would look like:
/app/main.js:
requirejs.config({
paths: {
jquery: "lib/jquery-1.11.0",
bootstrap: "lib/bootstrap"
},
shim: {
bootstrap: {
deps: ['jquery']
}
}
});
//Define dependencies and pass a callback when dependencies have been loaded
require(["jquery", "bootstrap"], function ($) {
//Bootstrap and jquery are ready to use here
//Access jquery and bootstrap plugins with $ variable
});
jquery.js and bootstrap.js would live under /app/lib in this case (along with require.js).
In your HTML you would have this script tag:
<script src="/app/lib/require.js" data-main="/app/main"></script>
This would load in bootstrap and jquery (in the correct order) and then pass those modules as parameter(s) (only jquery/$ is needed since bootstrap is just a plugin on top of jquery) to your callback function.
So taking Patrick's excellent answer (which helped me a lot), if you run your site against https://developers.google.com/speed/pagespeed/insights/ it will still give you a warning that
Eliminate render-blocking JavaScript and CSS in above-the-fold content
Your page has 1 blocking script resources
Remove render-blocking JavaScript:
http://mydomain/js/require.js
But taking the OP setup (and the one Google recommends) you can do this just before the </body> tag
<script type="text/javascript">
function requireJSOnload() {
var element = document.createElement("script");
element.src = "/js/require.js";
element.setAttribute('data-main', '/js/main');
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", requireJSOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", requireJSOnload);
else window.onload = requireJSOnload;
</script>
Now when you run against https://developers.google.com/speed/pagespeed/insights/ you will have no JS blocking scripts.
Starting from Bootstrap 5, the JavaScript file can be loaded in async directly.
While Patrick's answer is correct for Bootstrap 4 & below, Bootstrap 5 removes the jQuery dependency which allows for the full script to be loaded in both async or defer.

How to load a Javascript file within another Javascript file and execute file 2 before file 1?

I have written a jQuery plugin, say jquery.plugin.js. I want to use this plugin on a large number of sites.
What I want to do is to write a piece of js code at the top of jquery.plugin.js which will load the jquery.main.js and execute it so that $ is available to be used in jquery.plugin.js.
Thanks.
What you probably want to do is create a new tag in js
script = document.createElement('script');
script.src = 'URL-TO-JQUERY';
And then append that element before the first tag.
document.body.insertBefore(document.getElementsByTagName('script')[0], script);
This will most probably work as the script is inserted before any other js. (except in the head)
Yes, just a interval that checks if jQuery exists:
interval = setInterval(check, 100);
function check(){
if($.version){
// Exec script
}
}
This page may be useful for you
http://code.google.com/p/jquery-ajaxq/
with this script you can use files sequentially
Works only if jQuery is loaded already,
$.when($.getScript("path_to_script")).then(function() {
alert("loaded");
})​
Fiddle - http://jsfiddle.net/fLuDd/
Edit
var fileref = document.createElement('script')
fileref.setAttribute("type", "text/javascript")
fileref.setAttribute("src", 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js')
document.getElementsByTagName("head")[0].appendChild(fileref)
var t = setInterval(function() {
if (typeof(jQuery) == 'function') {
alert("jquery loaded");
clearInterval(t);
}
}, 2000);​
Fiddle - http://jsfiddle.net/fLuDd/1/
Just include the jquery.main.js above the jquery.plugin.js. It should work if you place the script tags in this order.
<script src="jquery.main.js"></script>
<script src="jquery.plugin.js"></script>
If you do not have full control over the html or if jQuery might be loaded from other places also, do this to check if it is loaded or not, and load only if needed.
Load from google
if (typeof jQuery == 'undefined') {
document.write('<script type="text/javascript" src="http://www.google.com/jsapi"></script>');
document.write('<script type="text/javascript">');
google.load("jquery", "1.4.2");
document.write('</script>');
}
Load from same server
if (typeof jQuery == 'undefined') {
document.write('<script type="text/javascript" src="path/to/jquery.min.js"></script>');
}
There are some AMD packages that do what you want, like requirejs, but... you'll have to load them first!
You could use a polling technique (load jQuery dynamically and poll until $ exists), not very elegant or efficient.
You could also attach an onload event handler to the dynamic jQuery script, which will trigger your plugin after loading jQuery. Of course such event handlers have cross-browser compatibility issues, so it's easier to write them... with jQuery.
Bottom line: it's a lot of trouble and you're usually better off just writing two script tags.
P.S.: Some of the above techniques are explained in this article:
http://www.stevesouders.com/blog/2008/12/27/coupling-async-scripts/

How to test if jQuery and certain other scripts have loaded?

I know about document.ready() but I don't want to wait for some content on external servers like Google Analytics, some ad serving content or anything else that isn't absolutely required for the website. I see this problem on sites that have user comments, and usually every single external piece of content has to be loaded before comments become available to use and even if one of the many CDNs is late, it blocks everything else.
I don't think you need to test it as much as you need to defer it. Here is a really simple example from Google.
(the following code copied from Google)
// Add a script element as a child of the body
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "deferredfunctions.js";
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;
Essentially, add a new script tag at the documentReady state when you're executing your code already.

Categories