Say I use google map api via two sites
<head>
<script
src="https://maps.googleapis.com/maps/api/js?sensor=false&hl=zh-CN&v=3.21&callback=initMap" async defer>
</script>
<script
src="http://ditu.google.cn/maps/api/js?sensor=false&hl=zh-CN&v=3.21&callback=initMap" async defer>
</script>
</head>
<body>
<script>
function initMap() {
//something
}
</script>
</body>
Sometimes I can't connect to the first site, but the code still works. Now I want to use the first site whenever I can connect to it. Is there a way to set the priority of the two sites?
You could load the first with javascript using document.createElement and add an onerror event handler that sets the src to the second source if the first fails:
<script>
var script = document.createElement('script');
script.src = 'http://ditu.google.cn/maps/api/js?sensor=false&hl=zh-CN&v=3.21&callback=initMap';
script.onerror = function() {
// if the above source fails to load, try this one
this.src = 'https://maps.googleapis.com/maps/api/js?sensor=false&hl=zh-CN&v=3.21&callback=initMap';
this.onerror = function() {
console.log('Nothing loaded!');
}
}
script.async = true;
script.defer = true;
document.body.appendChild(script);
</script>
Related
This question already has answers here:
How to make script execution wait until jquery is loaded
(15 answers)
Waiting for dynamically loaded script
(10 answers)
Closed 9 months ago.
I use an include function to dynamically include javascript files/headers/libraries.
The problem is that it seems loading the file happens in a multi-threaded way (tested on Chrome v102) and the js file is not yet loaded when I immetiately use functionnality after that.
Example with jQuery:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8"/>
<script type="text/javascript">
var include_once = function(url) {
/*
[additional code to check if 'url' was already included]
*/
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
document.head.appendChild(script);
}
include_once("https://code.jquery.com/jquery-3.6.0.min.js");
</script>
</head>
<body>
<script type="text/javascript">
/*
ok if I wait 'long enough' but is arbitrary
*/
setTimeout(function(){
$(document).ready(function(){
console.log("ready (timeout)");
});
}, 10);
/*
how to wait until window.$ is defined?
*/
$(document).ready(function(){
console.log("ready");
});
</script>
</body>
</html>
This code will likely give you a $ is not defined error, and ready (timeout) will be logged to the console.
How can I make my script wait until window.$ !== undefined here ?
I tried while(window.$ === undefined) {} but it completely blocks the script and $ is never defined.
you can promisfy the loading process, by creating a promise on first script and then on the second script check if the promise is resolved.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8"/>
<script type="text/javascript">
var isLoaded = new Promise((res,rej) => {
function include_once(url) {
/*
[additional code to check if 'url' was already included]
*/
var script = document.createElement("script");
script.type = "text/javascript";
script.onload = () => res()
script.onerror = () => rej()
script.src = url;
document.head.appendChild(script);
}
include_once("https://code.jquery.com/jquery-3.6.0.min.js");
})
</script>
</head>
<body>
<script type="text/javascript">
isLoaded.then(() => {
$(document).ready(function(){
console.log("ready");
});
})
</script>
</body>
</html>
i want to add a js script in another js page but its does'nt work i don't know i want to add jquery but still undifiend :
plugins.js :
var jquery = document.createElement("script");
jquery.type = "text/javascript";
jquery.src = "assets/vendor/js/jquery.min.js";
document.body.appendChild(jquery);
index.html :
<body>
<script src="./assets/js/plugins.js"></script>
<script src="./assets/js/main.js"></script>
</body>
</html>
and the bug :
Uncaught ReferenceError: $ is not defined
at main.js:1
If the ask is to load the scripts dynamically, you can load the jquery library via the plugins.js followed by the main.js file this way. This will work and work as intended.
<body>
<script>
(function () {
function loadScript(url, afterLoad) {
var script = document.createElement("script")
script.type = "text/javascript";
script.onload = function () {
afterLoad();
};
script.src = url;
document.getElementsByTagName("body")[0].appendChild(script);
}
loadScript('./assets/js/plugins.js', function () {
console.log('jquery has been added to DOM');
loadScript('./assets/js/main.js', function () {
console.log('jquery use now allowed');
});
});
})();
</script>
</body>
I try to add js files dynamically.
I found several guides for that and in Page inspector, they all seem like they work…
However, I cannot reference any code in the newly added files.
My three code examples that look like they work fine... but don't.
//v1
var th = document.getElementsByTagName('head')[0];
var s = document.createElement('script');
s.setAttribute('type', 'text/javascript');
s.setAttribute('src', scriptName);
th.appendChild(s);
DevExpress.localization.loadMessages(RddsDataNavigator_LanguagePack_en);
//v2
var s = document.createElement('script');
s.setAttribute('src', scriptName);
document.head.appendChild(s);
DevExpress.localization.loadMessages(RddsDataNavigator_LanguagePack_en);
//v3
let myScript = document.createElement("script");
myScript.setAttribute("src", scriptName);
document.head.appendChild(myScript);
DevExpress.localization.loadMessages(RddsDataNavigator_LanguagePack_en);
do i have to append the scripts differently or is my reference call wrong / not possible?
the Guides that exactly explain my requirement seem somehow not to work for me ?!
https://www.kirupa.com/html5/loading_script_files_dynamically.htm
Dynamically adding js to asp.net file
Thanks in advance for any help
The three methods to add a script element are essentially the same*.
As dynamically added script elements do not load the resources synchronously, you need to listen to the load event on the global object. DOMContentLoaded is another idea, but it fires too soon as it does not wait for resources to have loaded.
Here is a demo with loading jQuery asynchronously. The output shows the type of the jQuery variable, which will be "function" once that resource is loaded:
let scriptName = "https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.js";
// v3
let myScript = document.createElement("script");
myScript.setAttribute("src", scriptName);
document.head.appendChild(myScript);
console.log("Synchronous, jQuery =", typeof jQuery);
document.addEventListener("DOMContentLoaded", function () {
console.log("After DOMContentLoaded event, jQuery =", typeof jQuery);
});
window.addEventListener("load", function () {
console.log("After load event, jQuery =", typeof jQuery);
});
* The first version also defines the type attribute, but the HTML5 specification urges authors to omit the attribute rather than provide a redundant MIME type.
Consider this working example:
// dyn.js
window.zzz = 1;
<!--index.html-->
<html>
<head>
<script>
function includeJs(url)
{
if (!url) throw "Invalid argument url";
var script = document.createElement("script");
script.src = url;
document.head.appendChild(script);
}
includeJs("dyn.js");
function documentLoaded()
{
alert(window.zzz)
}
</script>
</head>
<body onload="javascript:documentLoaded()">
</body>
</html>
An obvious difference between your code and this is that the sample above loads the script during the document loading and the usage of the script code happens after the document has finished loading.
If you need to do a late-loading of a dynamic script depending on some run-time parameters, here are some options:
If you have control over the dynamically-loading script, you could add a function in your loader script and call it at the last line of the dynamically-loading script:
// dyn.js
window.zzz = 1;
if(typeof(dynamicLoadingFinished) != "undefined") dynamicLoadingFinished();
<!--index.html-->
<html>
<head>
<script>
function includeJs(url)
{
if (!url) throw "Invalid argument url";
var script = document.createElement("script");
script.src = url;
document.head.appendChild(script);
}
function documentLoaded()
{
includeJs("dyn.js");
window.dynamicLoadingFinished = function()
{
alert(window.zzz)
}
}
</script>
</head>
<body onload="javascript:documentLoaded()">
</body>
</html>
Another possible approach would be to use the good old XMLHttpRequest. It will allow you yo either force synchronous loading (which is not advisable because it will block all JavaScript and interactivity during loading, but in certain situations can be of use):
// dyn.js
window.zzz = 1;
<!--index.html-->
<html>
<head>
<script>
function includeJs(url)
{
if (!url) throw "Invalid argument url";
var request = new XMLHttpRequest();
request.open("GET", url, false);
request.send();
var script = document.createElement("script");
script.text = request.responseText;
document.head.appendChild(script);
}
function documentLoaded()
{
includeJs("dyn.js");
alert(window.zzz)
}
</script>
</head>
<body onload="javascript:documentLoaded()">
</body>
</html>
or load the script asynchronously and wait for the request to finish:
// dyn.js
window.zzz = 1;
<!--index.html-->
<html>
<head>
<script>
function includeJs(url, finished)
{
if (!url) throw "Invalid argument url";
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.onreadystatechange = function ()
{
if (request.readyState == 4 || request.readyState == 0)
{
if (request.status == "200")
{
var script = document.createElement("script");
script.text = request.responseText;
document.head.appendChild(script);
return finished();
}
else throw request.responseText;
}
};
request.send();
}
function documentLoaded()
{
includeJs("dyn.js", () => alert(window.zzz));
}
</script>
</head>
<body onload="javascript:documentLoaded()">
</body>
</html>
I believe the AJAX samples could be written also with the more modern fetch API (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).
I've implemented this answer in order to solve my problem but I still can't get the onload event fire.
I need a javascript solution, and I'm trying this on chrome. I know that I need to check for readystate for IE.
What am I missing here?
<script>
var script = document.createElement('script');
script.type = "type/javascript";
document.getElementsByTagName('head')[0].appendChild(script);
script.onload = function(){
console.info("After loading");
mdp.video.loadAllPlayers(".videoPlaceholder");
};
script.src = "/source.min.js";
</script>
Something like that
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script type="application/javascript">
var el = document.createElement('script');
el.src = "//cdnjs.cloudflare.com/ajax/libs/less.js/1.3.3/less.min.js"; // use what ever js file you want but valid one
el.onload = function(script) {
console.log(script + ' loaded!');
};
document.body.append(el);
</script>
</body>
</html>
I'm still learning by making my own loader; here's my progress:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
(function( $ ){
$.plugin = {
loadJS: function(src, onload, onerror){
var script = document.createElement("script");
script.type = "text/javascript";
script.src = src;
script.onload = onload;
script.onerror = onerror;
script.onreadystatechange = function () {
var state = this.readyState;
if (state === 'loaded' || state === 'complete') {
script.onreadystatechange = null;
onload();
}
};
document.body.appendChild(script);
},
loader: function(o) {
var loaded = ({js:[],css:[]});
// http://www.crockford.com/javascript/private.html
var that = this;
var phase = 0;
$.each(o["js"], function(key,src) {
that.loadJS(src,
function(){
loaded['js'].push(src);
});
});
console.log(loaded['js'].length)
// IF JS ALL LOADED, this is the main problem
if (loaded['js'].length == o["js"].length) {
alert('problem solved')
that.loadJS(o["script"]);
};
}
};
})( jQuery );
</script>
</head>
<body>
<script>
$(document).ready(function() {
$.plugin.loader({
js: [
'1.js', // async
'2.js', // async
'3.js', // async
'4.js' // async
],
script: '5.js', // after js loaded
debug: 1
});
});
</script>
</body>
</html>
the problem is i still dont get how stuff work in js. above the same it will load my js randomly as its async* assuming its all alert('this is x.js loaded') inside the 1-5.js
something like
// check goes randomly here
1.js or 1 js loaded
3.js 2 js loaded
2.js 3 js loaded
4.js 4 js loaded
// it should be here
so the logic is when my all js is load if (loaded['js'].length == o["js"].length) {alert('problem solved')}; should work. but it doent attach to the event somehow.
How can we check if all my js is loaded?
Looks like your check to see if they are all loaded is being run at the end of the loader function, so it will run immediately the async calls have been started. You need to move that check part into the the callback function thats passed to the .each function.
I ran into problems under IE 6 with a large JavaScript heavy app where occasionally external script loading was aborted without any discernable network trouble, so I ended up doing
<script src="sourcefile-1.js"></script>
...
<script src="sourcefile-n.js"></script>
<script src="last-loaded.js"></script>
<body onload="if(!window.allLoaded){/*reload*/}">...</body>
where last-loaded.js just did
window.allLoaded = true;
and where the reload code would redirect to an error page if a reload hadn't fixed the problem after a few tries.
This isn't the dynamic loader problem, but a similar approach should work with a dynamic loader as long as you can identify a point after which all external code should have loaded and you can run a very simple inlined script at that point.