I'm trying to do the following:
- from an HTML page I want to call a .js file in the header. I want this file to contain 2 functions, A and B, that I want to call at different times as the page loads.
This first part I have ready, my problem is:
-Function B is supposed to call another .js file, wait for it to complete loading and run some code specific to function B.
This is what I have so far:
<head><script type="text/javascript" src="first.js"></script></head>
I have this to call the different functions that are inside first.js
<script language="JavaScript" type="text/javascript">
functionA ();
</script>
Now inside first.js:
function functionA ()
{
alert("A runs!");
}
function functionB ()
{
alert("B runs!");
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "http://www.URL.com" ;
--some additional code--
}
Suggestions? Thanks!
First off, you don't "call a javascript file". You load the javascript file which causes it to get parsed and any top level code is executed. Once loaded, you can then call any functions in it.
So, to load a javascript file from functionB and then call a function in it, you can finish the dynamically loaded code you started with, but then you need to add a notification for when it is loaded:
function functionB () {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "http://www.URL.com" ;
script.onload = function() {
// call the function in the newly loaded scrip here
};
document.getElementsByTagName("head")[0].appendChild(script);
}
Here's a post with a loadScript function that takes a callback when the script is loaded.
Here's a post with a bit more capable function that can actually load scripts sequentially and also contains support code for older versions of IE (if that is required).
Making sure an external js file has been loaded across browsers requires more than a simple onload event; If you want a well-tested solution with added features, your best bet is using a library such as require.js.
Your code, after you include the require.js file somewhere, will look something like:
function functionA () {
alert("A runs!");
}
function functionB () {
alert("B runs!");
require(['yourotherfile'], function(myfile) { // no js extension, read more in require's docs
// --some additional code--
});
}
Related
first i want to check if jquery exists or not then move on to next function. But next function abc() is not being executed. Maybe somebody knows why!
window.onload = function () {
if (window.jQuery) {
localStorage.setItem("key", "abc");
} else {
script = document.createElement("script");
script.src = "https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js";
document.head.appendChild(script);
}
};
function abc() {
$(document).keypress(function (e) {
alert(e.key);
});
}
There are a few issues with that code. It sounds like you want to call abc when jQuery has been loaded, and for some reason you're allowing for the possibility it may or may not have been loaded prior to this code running. The issues I see are:
Setting a value in localStorage won't cause the function to be run; in fact, nothing in that code will cause abc to be run.
You're not declaring your script variable, which means the code is falling prey to what I call The Horror of Implicit Globals.
The load event on window happens really, really late in the page load process, after all images and other ancillary items are loaded. It's generally best to do your initialization sooner than that, by either using type="module" on your script element (if you're happy to use modules, which are handy) or by setting the defer attribute, or by putting the script at the very end of the body, just before the closing </body> tag (which is compatible with older browsers).
So here's what I might do instead, if I had to allow for this jQuery loaded/not loaded thing and I wasn't able to use modules (see comments):
// Use a wrapper if not using modules, to avoid creating unnecessary globals
(function() {
// Define your initialization function
function init() {
$(document).keypress(function (e) {
alert(e.key);
});
}
// If jQuery is loaded...
if (window.jQuery) {
// ...init
init();
} else {
// Otherwise, load it and init when it's loaded
var script = document.createElement("script");
// ^^^−−−−−−−−− prevents the horror of implicit globals
script.onload = init; // <=== Calls `init` when the script successfully loads
script.src = "https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js";
document.head.appendChild(script);
}
})();
I have the following JavaScript snippet, which I run in Developer tools console after opening a new tab in Google Chrome with http://example.com
var jq = document.createElement('script');
jq.src = 'https://code.jquery.com/jquery-latest.min.js';
document.head.appendChild(jq);
if (window.jQuery) {
window['jqy'] = jQuery.noConflict();
alert('jQuery is loaded');
}
else {
alert('jQuery not loaded');
}
It alerts jQuery not loaded for the first time, even when I see that the <script> is added to the DOM. Why?
Because the script will load in an async manner and will take a while to load completely after the script tag creation.
The alert method is executed just after the addition of script tag.
To achieve something like this you need a callback which will execute after the script is loaded completely.
Maybe something like this?
function loadScript(url, callback) {
var e = document.createElement("script");
e.src = url;
e.type = "text/javascript";
e.addEventListener('load', callback);
document.getElementsByTagName("head")[0].appendChild(e);
}
loadScript("https://code.jquery.com/jquery-latest.min.js", function() {
// This callback will fire once the script is loaded
if (window.jQuery) {
window['jqy'] = jQuery.noConflict();
alert('jQuery is loaded');
} else {
alert('jQuery not loaded');
}
});
Each Method in the javascript can take some time to complete the desired task allocated to it. Even appendChild function also will take some time to execute the method to complete.
But system won't wait for the task to complete and execute the next line. Because of that for the first time alert is coming with the jquery not loaded.
But if you execute the same function in the console again without loading it will alert you as a jquery is loaded because appendchild method completed his task successfully.
To overcome this issue need to add the task as a callback function. But append child is not having any callback function. So we need to use the setTimeOut function to solve this issue.
I want to defer loading of an external Javascript file until the page has loaded (and also I don’t want to block rendering if those external resources cannot be loaded). So I have this line
<script type="text/javascript" src=“//external.otherdomain.com/path/js/myresoures.js" defer></script>
However, when this file does eventually load, I want to run the following …
<script type="text/javascript">_satellite.pageBottom();</script>
However, as is, the above may run before the script has loaded. How do I run the above (or any) Javascript only after a remote resource has loaded? Keep in mind that if the external resource doesn’t load (it times out, for example), I don’t want to run the Javascript.
Thanks, - Dave
This can be achieved by an onload function.
You can dynamically load each... This example is pulled right from MDN. It will insert your external resource above the script you call importScript() then launch the callback after loading.
sSrc = your external script, fOnload = the callback
function importScript (sSrc, fOnload) {
var oScript = document.createElement("script");
oScript.type = "text\/javascript";
oScript.defer = true;
if (fOnload) { oScript.onload = fOnload; }
document.currentScript.parentNode.insertBefore(oScript, document.currentScript);
oScript.src = sSrc;
}
Usage:
importScript("//external.otherdomain.com/path/js/myresoures.js", function () { _satellite.pageBottom(); });
Or if jQuery is an option, use .getScript() like so:
$.getScript( "//external.otherdomain.com/path/js/myresoures.js", function () {_satellite.pageBottom();} );
Either of these options can be used in a <script> at the end of the page, after the fold as they say, ensuring the entire DOM loads first.
You can use jQuery's $(window).load();
see: http://api.jquery.com/load/
When using an importjs() type of function (see below for an example), jQuery doesn't seem to be loading before the code following it.
Here's a sample html file:
<html>
<head></head>
<body>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
function importjs(jsFile) {
var body = document.getElementsByTagName('head').item(0);
var scpt = document.createElement('script');
scpt.src = jsFile;
scpt.type = 'text/javascript';
body.appendChild(scpt);
}
var f1="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js";
//importjs(f1);
var $j=jQuery;
alert("hello stackoverflow!");
</script>
</body>
</html>
With the above code, the alert should successfully fire.
Next, comment out the first script block, i.e. the one explicitly loading jQuery, and uncomment the importjs(f1) line in the second script block. This time, the alert does not fire, at least in firefox and safari.
Now, put in an extra alert before the line "var $j=jQuery". For me, it works in both browsers, regardless of how long or short I wait. A setTimeout would probably also do the trick, but it's also not an ideal way to program something like this.
If javascript is single-threaded, why does the importjs fail? Is it because the new element created by importjs doesn't get 'executed' until the first block finishes, or should the new element be executed as soon as it is created?
There are several problems here:
you have jQuery duplicated, one in the html, one in the js
dynamically added javascript won't be available immediately
if you load scripts this way the dependant code should be in a callback function
function importjs(jsFile, callback) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = jsFile;
script.type = 'text/javascript';
script.onload = script.onreadystatechange = function() {
// execute callback
if (callback) callback();
// prevent memory leak in IE
script.onload = null;
head.removeChild(script);
};
head.appendChild(script);
}
then you should use it as:
importjs("jquery.js", function(){
// all jQuery dependant code
// goes here...
});
UPDATE
There is a more robust solution for including javascript files which allows you to:
include multiple files that are related
ensure they are executed in order
load them in a non-blocking way (parallel with other resources)
I'm still working on this script, but pretty much works right now. Be sure to check it out.
It combines the advantages of different techniques to give a huge benefit on page load time. Here is a related article: Loading Scripts Without Blocking
The syntax is:
include(['jquery.js','jquery-ui.js'], myjQueryCode); // executed in order
I'm downloading JQuery asynchronously:
function addScript(url) {
var script = document.createElement('script');
script.src = url;
document.getElementsByTagName('head')[0].appendChild(script);
}
addScript('jquery.js');
// non-jquery code ...
// jquery specific code like: $()...
As such - how do I call my JQuery specific code once JQuery is loaded (because since I'm downloading my JavaScript asynch - it's not blocking, which is good, but is trying to execute my JQuery specific code before JQuery has been loaded).
You can host a copy of the jquery file yourself. Then you can add a call to the callback function at the bottom of jquery.js:
/* jquery code goes here ... */
my_onload_callback();
For me this works (tested in FireFox 33.0.3):
if(typeof(jQuery) == "undefined"){
//create onload-callback function
window["__9384nalksdfalkj04320"] = function(){
console.log("jQuery=" + jQuery);
};
//load jQuery asynchronously
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("onload", "__9384nalksdfalkj04320();"); //register onload-callback listener function
script.setAttribute("src", "http://code.jquery.com/jquery-latest.min.js");
document.head.appendChild(script);
}
You can inline LabJs into your page (potentially, every page). On the downside, you're inlining a script over and over. On the upside, LabJs is pretty small - 4k minified - and it lets you handle complex asynchrony load patterns cross-browser with very simple code like:
<script>
// Minified LabJs goes here
</script>
<script>
function init() {
// Your code after jquery loads goes here
}
$LAB
.script('//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js')
.wait(init);
</script>
</body>
I'm not much on standard Javascript, but you may try doing something like this:
var script_object = new addScript('jquery.js');
script_object.onLoad('addScript("my_jquery_related.js")');
Admittedly, that's a mega shot in the dark.
If that doesn't work, maybe pass through your function as a callback variable in your JS loader:
addScript(url, function(){ function_to_call();})
function addScript(url, call_back_function) {
var script = document.createElement('script');
script.src = url;
document.getElementsByTagName('head')[0].appendChild(script);
call_back_function.call;
}
addScript('jquery.js');
That's all I got :\