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.
Related
I am trying to load a certain script after page load executes, something like this:
function downloadJSAtOnload(){
var element = document.createElement("script");
element.src = "scriptSrc";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
And while this script seems to execute and download 'scriptSrc', and append it right before the end of the body tag, it yields the following message (not an error) in the console (chrome)
Failed to execute 'write' on 'Document': It isn't possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened.
What does this even mean? And am I supposed to do something differently? Even though I get the expected behavior?
An asynchronously loaded script is likely going to run AFTER the document has been fully parsed and closed. Thus, you can't use document.write() from such a script (well technically you can, but it won't do what you want).
You will need to replace any document.write() statements in that script with explicit DOM manipulations by creating the DOM elements and then inserting them into a particular parent with .appendChild() or .insertBefore() or setting .innerHTML or some mechanism for direct DOM manipulation like that.
For example, instead of this type of code in an inline script:
<div id="container">
<script>
document.write('<span style="color:red;">Hello</span>');
</script>
</div>
You would use this to replace the inline script above in a dynamically loaded script:
var container = document.getElementById("container");
var content = document.createElement("span");
content.style.color = "red";
content.innerHTML = "Hello";
container.appendChild(content);
Or, if there was no other content in the container that you needed to just append to, you could simply do this:
var container = document.getElementById("container");
container.innerHTML = '<span style="color:red;">Hello</span>';
A bit late to the party, but Krux has created a script for this, called Postscribe. We were able to use this to get past this issue.
In case this is useful to anyone I had this same issue. I was bringing in a footer into a web page via jQuery. Inside that footer were some Google scripts for ads and retargeting. I had to move those scripts from the footer and place them directly in the page and that eliminated the notice.
You can also call
document.open() before document.write()
call
document.close()
when you're done.
It may not be best practice for a real webpage but for testing etc.. can be used.
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.
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.
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.
I don't want to call the JavaScript functions at the startup. The reason is simple, it will reduce the initial download size and the page will be appear faster. To do that I used the following code inside head section..
<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>
But it did not work...please help me
Usually, it's better to put scripts in the end of your body, and call them immediately.
Scripts block loading of the page, so putting them at the end of body allows the page to load quickly, and the javascript will load with page already ready.
document.head.appendChild(element)
You can use <script defer> (defer attribute on HTML script tag).
Example:
<script src="link/to/yourfile.js" defer></script>
defer will download the file during HTML parsing and will only execute it after the parser has completed. defer scripts are also guaranteed to execute in the order that they appear in the document.