Loading external JS file Asynchronously in document.ready() - javascript

I am trying to reference an external JS file asynchronously in document.read() event in application.
What am I currently doing to achieve this?
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = 'https://xxxx/jquery-3.2.1.js';
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
My Question:
Is there a better way to achieve the same thing with less lines of code using any other methods?

If you are using jQuery, then you could use the .getScript function.
jQuery.getScript("https://xxxx/jquery-3.2.1.js");

I think the way you are doing it now is a good way of doing it. But if you want fewer lines of code and/or want the html you are adding to be more visible, you could do this.
var t = createElement("div");
t.innerHTML = '<script type="text/javascript" async src="https://xxxx/jquery-3.2.1.js"></script>';
var x = document.querySelector("script");
x.parentNode.insertBefore(t.childNodes, x);

Related

Why getScript does not work from an external script?

I am trying to get the google recaptcha script to get loaded with
$.getScript("https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit");
If I put it into the <script> tags and inline the webpage, it loades the captcha correctly, while If I include the getScript, inside an external .js file still hosted on the same domain the javascript from recaptcha is not loaded. Is this a problem with the script itself or with getScript?
The script you're calling is rendered when the 'onload' event fires.
(function() {
if (!window['___grecaptcha_cfg']) {
window['___grecaptcha_cfg'] = {};
};
if (!window['___grecaptcha_cfg']['render']) {
// If the render time isn't set, set it to (window) onload //
window['___grecaptcha_cfg']['render'] = 'onload';
};
window['__google_recaptcha_client'] = true;
var po = document.createElement('script');
po.type = 'text/javascript';
po.async = true;po.src = 'https://www.gstatic.com/recaptcha/api2/r20150826120751/recaptcha__en.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(po, s);
})();
I'm not familiar with the google Captcha specs, but I think this can work. You just need to find the script url that executes in context. Hint: the URL probably won't say 'onload=onloadCallback' in it.

Is it possible to use a variable for a javascript reference

Instead of:
<script src="/scripts/myJsFile.v1.js" type="text/javascript></script>
Have something like
<script src="/scripts/myJsFile." + versionVar + ".js" type="text/javascript></script>
This way when we update the js version files the user won't have to clear their cache.
Not in that way, because you're mixing HTML and JavaScript together. HTML does not have JavaScript variables available.
What you can do, however, is adding the <script> tag dynamically, i.e. through JavaScript. That way, you obviously are able to use variables:
<script>
var versionVar = "1.0";
window.addEventListener('load', function() { // on load
var scriptTag = document.createElement('script'); // create tag
scriptTag.src = "/scripts/myJsFile." + versionVar + ".js" // set src attribute
scriptTag.type = "text/javascript"; //set type attribute
document.getElementsByTagName('head')[0].appendChild(scriptTag); // append to <head>
}, false);
</script>
Check out how Google loads their Analytics. Then maybe try something similar like:
(function() {
var versionVar = 9;
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.src = 'http://www' + '.google-analytics.com/ga' + versionVar + '.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();
You can't do this in your HTML file directly. But still you can do this inside an script tag if versopnVar is a JavaScript variable in your window context:
<script type="text/javascript">
var script = document.createElement('script');
script.setAttribute('src', '/scripts/myJsFile.' + versionVar + '.js');
script.setAttribute('type', 'text/javascript');
document.body.appendChild(script);
</script>
At the end, it's not a good aproach doing this. Please read this article at a list apart to get informed.
Alternative Style: Working With Alternate Style Sheets
It would probably be better to do something like
<script src="/scripts/myJsFile.js?v1" type="text/javascript></script>
Then, when you make and update:
<script src="/scripts/myJsFile.js?v2" type="text/javascript></script>
Which will cause most browsers to pull the file rather than pull from cache. This means that you won't have separate JS files. But will just be forcing the user to pull the most recent.
Also, if you want it to always pull the file you can, in a similar manner, append a random int.
You cannot do that straight out.
One way is with some server side code.
For example in php:
<?php $version = "1.0"; ?>
<script src="/scripts/myJsFile.<?php echo $version ?>.js" type="text/javascript></script>
Not exactly that way, but you can create a new script node with e.g. document.createElement and add it to the page.
var s = document.createElement("script");
s.src = ...
document.body.appendChild(s);
You can also use the document.write call to do the same...
You'd have to update your page to update the variable. Also, you'd have to update your javascript file name every time you changed it.
You can use a query string to make your JS unique.
<script src="/scripts/myJsFile.js?version=2" type="text/javascript></script>
marshall & I had the same Idea.
Also, you'd have to update your HTML file every time you updated your Javascript file.

Reference JS file in JS file

I have a Js function that I would like to:
Reference another js file
Pull a function out.
I would like to do this JS side and not reference on the actual page as I need this process to happen dynamically.
var h = document.getElementsByTagName('head')[0],
s = document.createElement('script');
s.type = 'text/javascript';
s.onload = function () { document.getElementById('hello').innerText = h.innerText; };
s.src = 'http://html5shiv.googlecode.com/svn/trunk/html5.js';
h.appendChild(s);
see: http://jsbin.com/uhoger
If you're working with the browser, jQuery has an helper function for it, $.getScript.
The only option I can think of is to dynamically insert a new script tag into the page targeting your desired script from your initial javascript. Just have your initial script insert the new <script> tag on load, or upon request and then test for availability.

which of these async loading methods is the best? document write?

Is there difference between these two async JavaScript loading methods?
<div class="g-plusone"></div>
<script type="text/javascript">
(function(d, t) {
var g = d.createElement(t),
s = d.getElementsByTagName(t)[0];
g.async = true;
g.src = 'https://apis.google.com/js/plusone.js';
s.parentNode.insertBefore(g, s);
})(document, 'script');
</script>
<script type="text/javascript">
//<![CDATA[
(function() {
document.write('<fb:like href="http://www.sandrophoto.com/' + location.pathname + '" send="true" width="360" show_faces="false" font=""></fb:like>');
var s = document.createElement('SCRIPT'),
s1 = document.getElementsByTagName('SCRIPT')[0];
s.type = 'text/javascript';
s.async = true;
s.src = 'http://connect.facebook.net/en_US/all.js#xfbml=1';
s1.parentNode.insertBefore(s, s1);
})();
//]]>
</script>
These two look conceptually similar in loading. They both create a new script tag and add it to the DOM which allows both to load asynchronously without dependencies on other script tags which must load in the order presented. There are minor differences in these implementations, but they look conceptually the same from the loading point of view.
The document.write() in the FB code causes some serialization with other loading events and could slow it down slightly (depends upon circumstances).
The most obvious difference is that the document.write approach writes the code into the doc exactly where it's placed, wherein the other method places the content into the container div specified.
There are some other differences too, and some other ways of loading scripts asynchronously.
Steve Souders has written an excellent article on the topic, http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/, which I recommend reading.

Get surrounding element of javascript

I have code that looks like this:
<div>
<script type="text/javascript">
(function() {
var s = document.createElement('script');
s.type = 'text/javascript';
s.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'localhost/chat/logo.js');
var t = document.getElementById('craftysyntax');
t.appendChild(s, t);
})();
</script>
<div>
I want the file that was loaded by async' to be able to do something like this (note: this is not working js code, but it is what I want to do)
parent.appendChild(abc);
which will add the child element abc in the parent div.
So, is there any way the script can reference its parent container?
Edit:
Why do I want to do this?
My website (an online store) uses a chat program with a link in the navigation bar that changes based on whether there is an operator logged in to the chat program. I am trying to convert the program to use an asynchronous loader, but the external js can not use document.write if it has been loaded asynchronously. I am trying to convert all of the document.write calls in the script to use the dom instead.
When your code is immediately executed like that, the last script element will be the current one (because of synchronous downloading and executing).
So you can get a reference to all script elements, and then get the last one using the length property minus one.
Then you can access its parent node with parentNode property.
<script type="text/javascript">
var allScripts = document.getElementsByTagName('script'),
thisScriptParent = allScripts[scripts.length - 1].parentNode;
</script>
jsFiddle.
Also, there is no need to use a ternary to check for https. Just use protocol-less (//localhost/chat/logo.js) and it will resolve to the parent site's protocol.
I don't think you can reliably get the script tag that the code is running from.
I'm not sure why your logo.js script doesn't just directly get the element by its id ("craftysyntax"), but if you are looking for a more general solution (where you could, say, add multiple such elements/scripts to the document in rapid succession, without having them mess each other up), you could do something like this:
<div>
<script type="text/javascript">
(function() {
var s = document.createElement('script');
s.type = 'text/javascript';
s.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'localhost/chat/logo.js');
var t = document.getElementById('craftysyntax');
if (window.global_chatElems == null)
global_chatElems = [];
global_chatElems.push(t);
t.appendChild(s);
})();
</script>
<div>
then in your logo.js script:
if (window.globalChatElems) {
for (var i=0; i<globalChatElems.length; i++)
processChatElem(globalChatElems[i]);
window.globalChatElems = null;
}
Of course, if you are only allowing one of these elements per page, everything is much simpler....no need to make the global be an array, it can just be a single variable.
I ran into an old friend from school and we discussed this and figured out this solution.
I will have the inline script create its own div named based on the current time (or something like that).
Then I can pass the id of the div to the other script in the query string.
(I already have the getQueryString function)
Inline
<script type="text/javascript">
var randval = "helpbox" + Math.floor(Math.random()*10000);
document.write('<div id="' + randval + '"></div>');
(function() {
var csc = document.createElement('script');
csc.type = 'text/javascript';
csc.src = 'a1.js?divid=' + randval;
var s = document.getElementById('help');
s.appendChild(csc, s);
})();
External
var my_div = document.getElementById(getQuerystring('divid'));

Categories

Resources