My html page creates a dynamic script, where I want to call a function defined in the script after the page loads. I am manually setting async=false on the dynamic script, but it still gets loaded after the DOM, which causes an error when I try to call the function that is not yet defined. Can someone tell me how to force the dynamic script to load before the DOMContentLoaded event. According to all documentation I can find, all scripts should be loaded before DOMContentLoaded event, unless async=true. I am seeing this behavior in Firefox and Chrome. Thank you.
Expected order of alerts:
Order alerts are actually firing:
HtmlPage1.html:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> <!--<script defer src="JavaScript.js" onload="alert('script loaded');" type="text/javascript"></script>--> <script type="text/javascript"> (function (n, t, a, e, co) { var r = t.createElement("script"); // dynamic scripts are async by default. Must change to ensure script loads before dom loaded. r.async = false; //r.defer = true; r.onload = function () { alert("script loaded"); }; r.src = a; var c = t.getElementsByTagName("script")[0]; c.parentNode.insertBefore(r, c); })(window, document, "JavaScript.js"); // have to delay calling TestFunction until after DOM loaded, because script needs to be loaded first document.addEventListener('DOMContentLoaded', (event) => { alert("dom load"); TestFunction(); }); </script> <div>Test Html Page</div> </body> </html>
JavaScript.js:
function TestFunction() {
alert("TestFunction called");
}
When you add a script tag to a page with js, it will have a low priority, and will be loaded with a delay compared to other high priority scripts, defer and async won't change anything, the loading process will start after the DOMContentLoaded event, because DOMContentLoaded does not take into account dynamically added scripts, it only tracks the loading of the initial html sent back by the server.
Which means a defer script might be loaded before a non-defer script because of the priority, if the defer script is loaded with high priority and the non-defer script is loaded with low priority.
You will need to listen to the load event on the script tag you added if you want to do that.
(function (n, t, a, e, co) {
var r = t.createElement("script");
// define an id
r.id = 'myScript';
r.onload = function () {
alert("script loaded");
};
r.src = a;
var c = t.getElementsByTagName("script")[0];
c.parentNode.insertBefore(r, c);
})(window, document, "JavaScript.js");
// listen to the load event of the actual script tag you added
myScript.addEventListener('load', (event) => {
alert("dom load");
TestFunction();
});
If you don't want to do that, you will have to replace your js with an actual script tag in the html :
<script src="JavaScript.js" onload="alert('script loaded');" type="text/javascript"></script>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', (event) => {
alert("dom load");
TestFunction();
});
</script>
now both scripts will be treated as high priority scripts because they are in the initial dom, and listening to DOMContentLoaded will work
Here is a screenshot of the network tab, with a dynamic script vs a static one :