Force dynamically loaded Javascript scripts to execute in order
When you dynamically add multiple <script> tags to an HTML document, the scripts load asynchronously. So if your second script depends on an earlier script, things might just not work. I tried using defer on the script tags but this was entirely unsuccessful.
My approach adds the <script> tags one at a time, and uses the load event to add the next script url in the list. My solution also allows you to add data-{key}={value} attributes to the final script node, so you can use the currentScript property for settings.
Note: I am adding the script tags to the end of the <body>. You may wish to edit the first line of my function if you wish for scripts to be added elsewhere.
Usage:
const scripts = [
'https://example.org/dependency1.js',
'https://example.org/dependency2.js',
'https://example.org/generate-table-of-contents.js'
];
const data_attributes = {
title: "Page Contents:",
button_text: "Generate Table of Contents"
};
load_scripts_in_order(scripts, data_attributes)
Load Scripts In Order:
/**
* Create a `<script>` node, setting an onload event to execute the next script in the list.
*
* @param scripts_array an array of javascript URLs with one or more entries
* @param final_script_settings key=>value array of `data-{key}={value}` settings to apply to only the last node in the array
*/
function load_scripts_in_order(scripts_array, final_script_settings){
const body = document.querySelector('body');
const script = document.createElement('script');
script.setAttribute('type', "text/javascript");
script.setAttribute('src', scripts_array[0]);
if (scripts_array.length > 1){
script.addEventListener('load',
load_scripts_in_order.bind(this, scripts_array.slice(1),
final_script_settings
)
);
}
if (scripts_array.length == 1){
for (const setting in final_script_settings){
script.setAttribute('data-'+setting, final_script_settings[setting]);
}
}
body.appendChild(script);
}