How to run code (Google/Doubleclick Ads) without block main thread - javascript

Is there any way to run Google Ads code without block main thread? Google Pagespeed Insights shows me a warning "Reduce the impact of third-party code": Third-party code blocked the main thread for ...
Third-Party Size Main-Thread Blocking Time
Google/Doubleclick Ads 193 KB 253 ms
I've placed a script to the end of the page in the footer.
<script data-ad-client="ca-pub-xxx" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
I tried to add "data-aload data-original=..." but it doesn't help. Maybe it would a right choice to use requestAnimationFrame() or setTimeOut(), but I don't know how to implement it on this.

You can add script dynamically. NB there is no need to add async since browser considers all dynamic script async by default
const loadScript = (src, id, callback) => {
const script = document.createElement('script');
script.src = src; // URL for the third-party library being loaded.
script.id = id; // e.g., googleMaps or stripe
script.defer = true; // make sure that browser will run script after page loaded
document.body.appendChild(script);
script.onload = () => {
if (callback) callback(); // conditional callback
};
};

Related

Google Maps callback not always triggering

Problem: It seems like when loading the Google Maps script, the callback is not performed. It might be related to how to load the Google Maps script.
Context: My website displays a Map in the frontpage when certain minimum viewport conditions are met. Specifically, I avoid loading it when I'm on mobile. I do not want to use jQuery :)
Implementation: The way I'm doing it is by first loading a small handcrafted script (google-map.js), which does a bunch of things and ends with:
function dynamicallyLoadScript(url) {
var script = document.createElement("script");
script.src = url;
script.type = "text/javascript";
script.defer = true;
document.head.appendChild(script);
};
// Load Google Maps when NOT on mobile
if ( ! mobile ) {
dynamicallyLoadScript('https://maps.googleapis.com/maps/api/js?key=wIzaScChUs5NxF3Z5LZoxkAS4wca9A7Pk53I024&callback=initMap');
}
(The JS key is fake).
Outcome: This actually works when I load the site for the first time. I see that google-map.js is loaded, the Google Maps script tag is added to the head, and both resources are loaded and working well. But sometimes (!) when I refresh, the map stops loading and upon inspection I see that the script tag was added successfully, and the resource is loaded, but the initMap() callback function hasn't triggered. If I go to the console, it does fire.
Since this happens only sometimes (and never upon a fresh load without cache), I think it might have something to do with a race condition or just with how cache works. But I'm not sure how to address it. Thoughts?
Solution in a nutshell: This is not a very elegant solution imho, but I figured that what I needed to create is some retry logic for loading initMap() when it runs before it should. In other words, I'm diagnosing this as a race condition present when cache is available.
Implementation: Added a small function to check every 0.1 seconds if the DOM has an element that only exists when the map is fully loaded. When so, the timer stops, but otherwise, it runs the initMap() function.
function checkMaps() {
if (document.getElementsByClassName("gm-style").length == 0) {
initMap();
} else {
clearInterval(checker);
}
}
checker = setInterval(checkMaps, 100);

Load jQuery Only If Not Present without document.write

is there any way to load jQuery file if it's not present without using document.write
<script>
window.jQuery || document.write('<script src="/path/to/your/jquery"><\/script>');
</script>
this way is good but it has major issue because if the visitor has slow connection the browser will prevent it from executing
when it happen I get this warning
file is invoked via document.write. The network request for this script MAY
be blocked by the browser in this or a future page load due to poor
network connectivity
I tried many solutions but nothing worked
You can pass a load callback to the IFFE that will be executed when the script loads or invoked immediately if jQuery exists.
var load = function(){
// your jQuery code goes here
$('#hello').html('jQuery Loaded');
};
(function(window, loadCallback){
if(!window.jQuery){
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://code.jquery.com/jquery-3.3.1.min.js";
script.onload = loadCallback;
document.head.appendChild(script);
}else{
loadCallback();
}
})(window, load);
<div id="hello"></div>

"asynchronously-loaded external script" error

I am getting this error with my code "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."
I am trying to load every 25 seconds new ad banner from third site.
mFl();
function mFl() {
if (document.getElementsByClassName('adposition').length > 0) { loadMe("adposition","http://third.tld/b?z=1&u=a&width=728&height=90"); }
setTimeout(mFl, 25000);
}
function loadMe(className, scriptName) {
var docHeadObj = document.getElementsByClassName( className )[0];
docHeadObj.innerHTML = "";
var ttt = Math.floor(Date.now() / 1000);
var dynamicScript = document.createElement("script");
dynamicScript.type = "text/javascript";
dynamicScript.src = scriptName+ "&uunique=" + ttt;
docHeadObj.appendChild(dynamicScript);
}
Any workaround for this please?
Try using https://github.com/krux/postscribe plugin. As it mentioned in the repo.
Remote scripts, especially ads, block the page from doing anything else while they load. They contribute a large % to load times which affects your bottom line. Asynchronous ads do not block the page and can be delivered after core content - Async FTW.
Why is it so hard to deliver ads asynchronously? Because they may
contain calls to document.write, which expects to be handled
synchronously. PostScribe lets you deliver a synchronous ad
asynchronously without modifying the ad code.

Load javascript in consecutive order after browser load event

What am I trying to do? In an attempt to speed up my website I am loading non-essential javascript after the browser load event. (So the JS files are not render blocking) This is currently functioning correctly.
What is the problem? The problem is sometimes the non-essential javascript depends on other libraries and plus those libraries need to load first.
What have I tried to do to fix the problem? In an attempt to fix the problem I have added a delay event to library dependent javascript. While this works sometimes, the load times of a JS file varies between refreshes and at times can load before the library even with a delay.
QUESTION: Does anyone know of a better way for me the load JS files only after the first JS file has loaded? (See code below)
<script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
var element2 = document.createElement("script");
var delay=40;
element.src = "http://119.9.25.149/sites/all/themes/bootstrap/bootstrap_nova/js/highcharts.js";
element2.src = "http://119.9.25.149/sites/all/themes/bootstrap/bootstrap_nova/js/future-plastic.js";
document.body.appendChild(element);
setTimeout(function(){
document.body.appendChild(element2);
},delay);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
</script>
As you can see from the above, I am trying to load the highcharts js file before I load the future-plastic file.
You're not the first to have this problem, thankfully. There's a lot of difficult solutions around this problem, including using a module loader as suggested in the comment (which I agree is the best long term solution, because they account for more browsers and flexibility, but it's a lot to learn to solve one small problem).
The place to start learning about this problem and the ways to tackle it are all over the web. This is a pretty good resource: http://www.html5rocks.com/en/tutorials/speed/script-loading/
You may want to try defer if you don't have to support Opera Mini or IE9. Or, you can load sync and execute as it loads- their examples is this:
[
'//other-domain.com/1.js',
'2.js'
].forEach(function(src) {
var script = document.createElement('script');
script.src = src;
script.async = false;
document.head.appendChild(script);
});
The reason why this might work (different browser implement this differently) is because the default is to load dynamically generated script tags are set to async by default, if you set it to false: "they’re executed outside of document parsing, so rendering isn’t blocked while they’re downloaded"
You should use ScriptElement.onload:
var pre = onload;
onload = function(){
if(pre)pre();
var doc = document, bod = doc.body;
function C(t){
return doc.createElement(t);
}
function downloadJSAtOnload(){
var s = C('script'), ns = C('script'), h = doc.getElementsByTagName('head')[0];
var u = 'http://119.9.25.149/sites/all/themes/bootstrap/bootstrap_nova/js/';
s.type = ns.type = 'text/javascript'; s.src = u+'highcharts.js'; h.appendChild(s);
s.onload = function(){
ns.src = u+'future-plastic.js'; h.appendChild(ns);
}
}
downloadJSAtOnload();
}
Note: The first onload is window.onload, since window is implicit.

Loading scripts dynamically

I'm loading a few YUI scripts dynamically in my code in response to an Ajax request. The DOM and the page is fully loaded when the request is made - it's a response for an user event.
I add the <scripts> tag to head as children, but I stumbled in a few problems:
I add two YUI scripts hosted at the Yahoo! CDN and an inlined script of my own responsible for creating object, adding event listeners and rendering the YUI widgets. But I when my script run the YUI scripts are not loaded yet giving me errors and not running as I expect.
There's a way to only run my script (or define a function to be run) when YUI scripts are fully loaded?
Have you tried an onload event?
Edited:(thanks Jamie)
var script = document.createElement("script");
script.type = "text/javascript";
script.src = src;
//IE:
if(window.attachEvent && document.all) {
script.onreadystatechange = function () {
if(this.readyState === "complete") {
callback_function(); //execute
}
};
}
//other browsers:
else {
script.onload = callback_function; //execute
}
document.getElementsByTagName("head")[0].appendChild(script);
If you're using YUI 2.x I highly recommend using the YUI Get utility, as it's designed to handle just this sort of a problem.
If you are loading multiple individual script files from the Yahoo! CDN, you'll need to makes sure both are loaded before executing your dependent code. You can avoid this using the combo handler. See the Configurator to get what the script url should be to load both/all needed YUI files from one url.
http://developer.yahoo.com/yui/articles/hosting/
With that in mind, assuming you must load the YUI files asynchronously, you should use an onload/onreadystatechange handler as noted by digitalFresh.
I would recommend the following pattern, however:
(function (d) {
var s = d.createElement('script'),
onEvent = ('onreadystatechange' in s) ? 'onreadystatechange' : 'onload';
s[onEvent] = function () {
if (("loaded,complete").indexOf(this.readyState || "loaded") > -1) {
s[onEvent] = null;
// Call your code here
YAHOO.util.Dom.get('x').innerHTML = "Loaded";
}
};
// Set the src to the combo script url, e.g.
s.src = "http://yui.yahooapis.com/combo?2.8.1/...";
d.getElementsByTagName('head')[0].appendChild(s);
})(document);
You could use a setTimeout() to run some function that just checks if it's loaded - check something like
if (typeof YUI_NAMESPACED_THING !== "undefined") runCode()
EDIT Thanks, CMS
If I understand this correctly, your ajax response with this:
<script href="yui-combo?1"></script>
<script href="yui-combo?2"></script>
<p>some text here</a>
<script>
// using some of the components included in the previous combos
// YAHOO.whatever here...
</script>
If this is the case, this is a clear case in which you should use dispatcher plugin. Dispatcher will emulate the browser loading process for AJAX responses. Basically it will load and execute every script in the exact order.
Best Regards,
Caridy

Categories

Resources