Defer Loading of javascript for google page insights - javascript

I have a code for defer loading of javascript I am wondering if the code will load the scripts in order (JQuery.min first) according to where they are in the code ?
function downloadJSAtOnload() {
var element01 = document.createElement("script");
element01.src = "js/jquery.min.js";
document.body.appendChild(element01);
var element02 = document.createElement("script");
element02.src = "js/plugins.js";
document.body.appendChild(element02);
var element03 = document.createElement("script");
element03.src = "js/scripts.js";
document.body.appendChild(element03);
var element04 = document.createElement("script");
element04.src = "js/SmoothScroll.min.js";
document.body.appendChild(element04);
var element05 = document.createElement("script");
element05.src = "js/contact-form.js";
document.body.appendChild(element05);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
If this doesn't load JQuery.min first and then the other js files how can you make JQuery.min the first script to load and then the rest after that has loaded?
Also I am guessing for example the contact-form.js will be one of the first to finish loading as it's small so this could cause the Uncaught ReferenceError: $ is not defined I'm guessing because the JQuery.min hasn't finished downloading so how would you solved this ? I'm guessing an listener / if finished loading load the others else wait...
Thanks in advance

found here Load jQuery with JavaScript using Promises
function loadScript(url) {
return new Promise(function(resolve reject) {
var script = document.createElement("script");
script.onload = resolve;
script.onerror = reject;
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
});
}
function loadjQuery() {
if (window.jQuery) {
// already loaded and ready to go
return Promise.resolve();
} else {
return loadScript('https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js');
}
}
// Usage:
loadjQuery().then(function() {
// code here that uses jQuery
}, function() {
// error loading jQuery
});

This is quick, but I think it should work.
function downloadJSAtOnload() {
var element01 = document.createElement("script");
element01.src = "js/jquery.min.js";
document.body.appendChild(element01);
element01.onload = function() {
var element02 = document.createElement("script");
element02.src = "js/plugins.js";
document.body.appendChild(element02);
var element03 = document.createElement("script");
element03.src = "js/scripts.js";
document.body.appendChild(element03);
var element04 = document.createElement("script");
element04.src = "js/SmoothScroll.min.js";
document.body.appendChild(element04);
var element05 = document.createElement("script");
element05.src = "js/contact-form.js";
document.body.appendChild(element05);
}
}

Related

How to dynamically load script in React

I am having problem loading a script from within React side
This is the script:
<script>!function(e,t,s,i){var n="InfogramEmbeds",o=e.getElementsByTagName("script")[0],d=/^http:/.test(e.location)?"http:":"https:";if(/^\/{2}/.test(i)&&(i=d+i),window[n]&&window[n].initialized)window[n].process&&window[n].process();else if(!e.getElementById(s)){var r=e.createElement("script");r.async=1,r.id=s,r.src=i,o.parentNode.insertBefore(r,o)}}(document,0,"infogram-async","https://e.infogram.com/js/dist/embed-loader-min.js");</script>
I tried something like this:
const script = document.createElement("script");
script.src = scriptUrl;
script.charset = "utf-8";
script.async = true;
script.onload = function() {
!function(e,t,s,i){var n="InfogramEmbeds",o=e.getElementsByTagName("script")[0],d=/^http:/.test(e.location)?"http:":"https:";if(/^\/{2}/.test(i)&&(i=d+i),window[n]&&window[n].initialized)window[n].process&&window[n].process();else if(!e.getElementById(s)){var r=e.createElement("script");r.async=1,r.id=s,r.src=i,o.parentNode.insertBefore(r,o)}}(document,0,"infogram-async","https://e.infogram.com/js/dist/embed-loader-min.js");
};
document.body.appendChild(script);
If I add the script directly into header than it works perfectly fine.
All you need to do is call the function inside componentDidMount and append the child into head like this
componentDidMount() {
const script = document.createElement("script");
script.src = 'https://www.google.com'; // whatever url you want here
script.charset = "utf-8";
script.async = true;
script.onload = function () {
!function (e, t, s, i) { var n = "InfogramEmbeds", o = e.getElementsByTagName("script")[0], d = /^http:/.test(e.location) ? "http:" : "https:"; if (/^\/{2}/.test(i) && (i = d + i), window[n] && window[n].initialized) window[n].process && window[n].process(); else if (!e.getElementById(s)) { var r = e.createElement("script"); r.async = 1, r.id = s, r.src = i, o.parentNode.insertBefore(r, o) } }(document, 0, "infogram-async", "https://e.infogram.com/js/dist/embed-loader-min.js");
};
document.head.appendChild(script);
}
I have created an npm package, a react hook to load a script dynamically. You can use that to load script dynamically in your react application. It will add script in the head or as child of any specified HTML element.
Here is the link to the package https://www.npmjs.com/package/use-script-loader

Set response data from external JS script

I have this script
<script>
function loadJS(src, callback) {
var s = document.createElement('script');
s.src = src;
s.async = true;
s.onreadystatechange = s.onload = function() {
var state = s.readyState;
if (!callback.done && (!state || /loaded|complete/.test(state))) {
callback.done = true;
callback();
}
};
document.getElementsByTagName('head')[0].appendChild(s);
}
loadJS('/script/script.js', function() {
// put your code here to run after script is loaded
});
</script>
And I can't figure out how can I get response data from the script I'm trying to load.
Basically, this script contains a function that does something and then returns some value.
I know that in jQuery analog in would be just data argument in getScript function, but I only have native JS here.
What and where should I add to get response data in my script?
Assuming that your script contains a function declared in a global scope, you can simply include this script and then execute any function / access any member from this script:
After your script has been loaded and executed, you can work with it just like with a simple script which is a part of your current document.
Here is a demo which loads jQuery script from Google CDN and then outputs jQuery version (which is a part of jQuery library):
function loadJS(src, callback) {
var s = document.createElement('script');
s.src = src;
s.async = true;
s.onreadystatechange = s.onload = function() {
var state = s.readyState;
if (!callback.done && (!state || /loaded|complete/.test(state))) {
callback.done = true;
callback();
}
};
document.getElementsByTagName('head')[0].appendChild(s);
}
console.log("typeof jQuery: " + typeof jQuery); // jQuery not loaded
loadJS("https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js", function() {
console.log("typeof jQuery: " + typeof jQuery + ", version = " + jQuery.fn.jquery); // jQuery has been loaded
});

can't run jQuery functions after appending jQuery from same file

I'm appending into my page multiple scripts including jQuery, jQuery migrate... all from same .js file
this is how it looks:
function appendScript(pathToScript, run) {
var head = document.getElementsByTagName("head")[0];
var js = document.createElement("script");
js.type = "text/javascript";
if(run == true){
js.onreadystatechange = function () {
if (this.readyState == 'complete') runFunctions();
}
js.onload = runFunctions;
}
js.src = pathToScript;
head.appendChild(js);
}
appendScript("http://code.jquery.com/jquery-latest.min.js");
appendScript("http://code.jquery.com/jquery-migrate-1.3.0.min.js", true);
function runFunctions(){
console.log('test') // all good till here
// here i have only jquery functions
$('#myDiv').addClass('test');
alert("this doesn't work");
....
}
My problem is that I can't run $(document).ready or any jQuery function, only javascript.
Tried with timeout too. Also I already have 1 x $(window).bind("load", function(){...} so I don't need 1 more
Since jQuery Migrate depends on jQuery, you need to wait until loading the next script.
Here is a working example (I also cleaned up some variables).
function appendScript(src, callback) {
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.type = "text/javascript";
if (callback) {
script.onload = callback;
}
script.src = src;
head.appendChild(script);
}
appendScript("https://code.jquery.com/jquery-latest.min.js", function() {
appendScript("https://code.jquery.com/jquery-migrate-1.3.0.min.js", function() {
document.body.innerHTML = 'Loaded jQuery version ' + jQuery.fn.jquery;
});
});
See working jsfiddle.

Dynamically add script tag with src that may include document.write

I want to dynamically include a script tag in a webpage however I have no control of it's src so src="source.js" may look like this.
document.write('<script type="text/javascript">')
document.write('alert("hello world")')
document.write('</script>')
document.write('<p>goodbye world</p>')
Now ordinarily putting
<script type="text/javascript" src="source.js"></script>
In the head works fine but is there any other way I can add source.js dynamically using something like innerHTML?
jsfiddle of what i've tried
var my_awesome_script = document.createElement('script');
my_awesome_script.setAttribute('src','http://example.com/site.js');
document.head.appendChild(my_awesome_script);
You can use the document.createElement() function like this:
function addScript( src ) {
var s = document.createElement( 'script' );
s.setAttribute( 'src', src );
document.body.appendChild( s );
}
There is the onload function, that could be called when the script has loaded successfully:
function addScript( src, callback ) {
var s = document.createElement( 'script' );
s.setAttribute( 'src', src );
s.onload=callback;
document.body.appendChild( s );
}
It's almost a decade later and nobody bothers to write the Promise version, so here is mine (based on this awnser):
function addScript(src) {
return new Promise((resolve, reject) => {
const s = document.createElement('script');
s.setAttribute('src', src);
s.addEventListener('load', resolve);
s.addEventListener('error', reject);
document.body.appendChild(s);
});
}
Usage
try {
await addScript('https://api.stackexchange.com/js/2.0/all.js');
// do something after it was loaded
} catch (e) {
console.log(e);
}
a nice little script I wrote to load multiple scripts:
function scriptLoader(scripts, callback) {
var count = scripts.length;
function urlCallback(url) {
return function () {
console.log(url + ' was loaded (' + --count + ' more scripts remaining).');
if (count < 1) {
callback();
}
};
}
function loadScript(url) {
var s = document.createElement('script');
s.setAttribute('src', url);
s.onload = urlCallback(url);
document.head.appendChild(s);
}
for (var script of scripts) {
loadScript(script);
}
};
usage:
scriptLoader(['a.js','b.js'], function() {
// use code from a.js or b.js
});
When scripts are loaded asynchronously they cannot call document.write. The calls will simply be ignored and a warning will be written to the console.
You can use the following code to load the script dynamically:
var scriptElm = document.createElement('script');
scriptElm.src = 'source.js';
document.body.appendChild(scriptElm);
This approach works well only when your source belongs to a separate file.
But if you have source code as inline functions which you want to load dynamically and want to add other attributes to the script tag, e.g. class, type, etc., then the following snippet would help you:
var scriptElm = document.createElement('script');
scriptElm.setAttribute('class', 'class-name');
var inlineCode = document.createTextNode('alert("hello world")');
scriptElm.appendChild(inlineCode);
document.body.appendChild(scriptElm);
You can try following code snippet.
function addScript(attribute, text, callback) {
var s = document.createElement('script');
for (var attr in attribute) {
s.setAttribute(attr, attribute[attr] ? attribute[attr] : null)
}
s.innerHTML = text;
s.onload = callback;
document.body.appendChild(s);
}
addScript({
src: 'https://www.google.com',
type: 'text/javascript',
async: null
}, '<div>innerHTML</div>', function(){});
A one-liner (no essential difference to the answers above though):
document.body.appendChild(document.createElement('script')).src = 'source.js';
This Is Work For Me.
You Can Check It.
var script_tag = document.createElement('script');
script_tag.setAttribute('src','https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js');
document.head.appendChild(script_tag);
window.onload = function() {
if (window.jQuery) {
// jQuery is loaded
alert("ADD SCRIPT TAG ON HEAD!");
} else {
// jQuery is not loaded
alert("DOESN'T ADD SCRIPT TAG ON HEAD");
}
}
Loads scripts that depends on one another with the right order.
Based on Satyam Pathak response, but fixed the onload.
It was triggered before the script actually loaded.
const scripts = ['https://www.gstatic.com/firebasejs/6.2.0/firebase-storage.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-firestore.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-app.js']
let count = 0
const recursivelyAddScript = (script, cb) => {
const el = document.createElement('script')
el.src = script
if(count < scripts.length) {
count ++
el.onload = () => recursivelyAddScript(scripts[count])
document.body.appendChild(el)
} else {
console.log('All script loaded')
return
}
}
recursivelyAddScript(scripts[count])
Well, there are multiple ways you can include dynamic javascript,
I use this one for many of the projects.
var script = document.createElement("script")
script.type = "text/javascript";
//Chrome,Firefox, Opera, Safari 3+
script.onload = function(){
console.log("Script is loaded");
};
script.src = "file1.js";
document.getElementsByTagName("head")[0].appendChild(script);
You can call create a universal function which can help you to load as many javascript files as needed. There is a full tutorial about this here.
Inserting Dynamic Javascript the right way
No one mentioned it, but you can also stick the actual source code into a script tag by making a URL out of it using URL and Blob:
const jsCode = `
// JS code in here. Maybe you extracted it from some HTML string.
`
const url = URL.createObjectURL(new Blob([jsCode]))
const script = document.createElement('script')
script.src = url
URL.revokeObjectURL(url) // dispose of it when done
as for the jsCode, you may have gotten it from some HTML.
Here's a more full example of how you'd handle any number of scripts in an HTML source:
main()
async function main() {
const scriptTagOpen = /<script\b[^>]*>/g
const scriptTagClose = /<\/script\b[^>]*>/g
const scriptTagRegex = /<script\b[^>]*>[\s\S]*?<\/script\b[^>]*>/g
const response = await fetch('path/to/some.html')
const html = await response.text()
someElement.innerHTML = html
// We need to get the script tags and manually add them to DOM
// because otherwise innerHTML will not execute them.
const codes =
html
.match(scriptTagRegex)
?.map(code => code.replace(scriptTagOpen, '').replace(scriptTagClose, ''))
.map(code => URL.createObjectURL(new Blob([code]))) || []
for (const code of codes) {
const script = document.createElement('script')
script.src = code
someElement.append(script)
URL.revokeObjectURL(code)
}
}
the only way to do this is to replace document.write with your own function which will append elements to the bottom of your page. It is pretty straight forward with jQuery:
document.write = function(htmlToWrite) {
$(htmlToWrite).appendTo('body');
}
If you have html coming to document.write in chunks like the question example you'll need to buffer the htmlToWrite segments. Maybe something like this:
document.write = (function() {
var buffer = "";
var timer;
return function(htmlPieceToWrite) {
buffer += htmlPieceToWrite;
clearTimeout(timer);
timer = setTimeout(function() {
$(buffer).appendTo('body');
buffer = "";
}, 0)
}
})()
I tried it by recursively appending each script
Note If your scripts are dependent one after other, then position will need to be in sync.
Major Dependency should be in last in array so that initial scripts can use it
const scripts = ['https://www.gstatic.com/firebasejs/6.2.0/firebase-storage.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-firestore.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-app.js']
let count = 0
const recursivelyAddScript = (script, cb) => {
const el = document.createElement('script')
el.src = script
if(count < scripts.length) {
count ++
el.onload = recursivelyAddScript(scripts[count])
document.body.appendChild(el)
} else {
console.log('All script loaded')
return
}
}
recursivelyAddScript(scripts[count])
Here is a minified snippet, same code as Google Analytics and Facebook Pixel uses:
!function(e,s,t){(t=e.createElement(s)).async=!0,t.src="https://example.com/foo.js",(e=e.getElementsByTagName(s)[0]).parentNode.insertBefore(t,e)}(document,"script");
Replace https://example.com/foo.js with your script path.
window.addEventListener("load", init);
const loadScript = async (url) => {
const response = await fetch(url);
const script = await response.text();
eval(script);
}
function init() {
const wistiaVideo = document.querySelector(".wistia_embed");
if ("IntersectionObserver" in window && "IntersectionObserverEntry" in window && "intersectionRatio" in window.IntersectionObserverEntry.prototype) {
let lazyVideoObserver = new IntersectionObserver(function (entries, observer) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
setTimeout(() => loadScript("//fast.wistia.com/assets/external/E-v1.js"), 1000);
lazyVideoObserver.unobserve(entry.target);
console.log("E-v1.js script loaded from fast.wistia.com");
}
});
});
lazyVideoObserver.observe(wistiaVideo);
}
}
<div style="height: 150vh; background-color: #f7f7f7;"></div>
<h1>Wistia Video!</h1>
<div class="wistia_embed wistia_async_29b0fbf547" style="width:640px;height:360px;"> </div>
<h1>Video Ended!</h1>

How to call the function in this file?

I pasted the code given in this link to a file called md5.js.
http://www.webtoolkit.info/javascript-md5.html
I am not able to call the function in my below code. Please assist me.
function inc(filename)
{
var body = document.getElementsByTagName('body').item(0);
script = document.createElement('script');
script.src = filename;
script.type = 'text/javascript';
body.appendChild(script)
}
function CheckCaptcha()
{
var CaptchaWord="";
CaptchaWord = document.getElementById('studentusername').value;
inc("md5.js");
//Add MD5 function here.
}
You can try adding an event handler for the scripts onload and continuing your code from there.
e.g.
function inc(fname, callback)
{
var body = document.getElementsByTagName('body').item(0);
script = document.createElement('script');
script.src = filename;
script.type = 'text/javascript';
script.onload = callback;
body.appendChild(script);
}
function CheckCaptcha()
{
var CaptchaWord="";
CaptchaWord = document.getElementById('studentusername').value;
inc("md5.js", function() {
//Add MD5 function here.
});
}
The alternative to this approach (which will work far more rebustly as well) is to include the md5 script directly as opposed to using the inc function.
<script src="/path/to/md5.js" type="text/javascript"></script>
<script type="text/javascript">
function CheckCaptcha()
{
var CaptchaWord="";
CaptchaWord = document.getElementById('studentusername').value;
return md5(CaptchaWord); //or something
}
</script>
As onload doesnt work in ie you need to add onreadystatechange.
function inc(fname, callback)
{
var body = document.getElementsByTagName('body').item(0);
script = document.createElement('script');
script.src = filename;
script.type = 'text/javascript';
script.onload = callback;
script.onreadystatechange= function () {
if (this.readyState == 'complete') callback();
}
body.appendChild(script);
}
function CheckCaptcha()
{
var CaptchaWord="";
CaptchaWord = document.getElementById('studentusername').value;
inc("md5.js", function() {
//Add MD5 function here.
});
}

Categories