14

I have this simple function which loads scripts into the current DOM:

function loadscripts ( async ) { if( async === undefined ) { async = false; } var scripts = []; var _scripts = ['jquery.min.js', 'bootstrap.min.js', 'plugins.js', 'main.js']; for(var s in _scripts) { scripts[s] = document.createElement('script'); scripts[s].type = 'text/javascript'; scripts[s].src = _scripts[s]; scripts[s].async = async; document.getElementsByTagName('head').appendChild( scripts[s] ); } } 

They are loaded fine and without no errors. I know there are event handlers when loading scripts programmatically:

  • onreadystatechange, and
  • onload, etc

Now I would like to wish to do the following:

  • Load first script from the array, and when the event handlers are COMPLETE load the next one, and so on (recursively).

Sorry, I have not provided the onreadystatechange and onload events in my function.

3
  • I suggest you to try headjs. It's great to manage several scripts! Commented Mar 8, 2013 at 11:01
  • @MiguelRodrigues - thanks for suggestion, but I'm making my own headjs similar script :) Commented Mar 8, 2013 at 11:03
  • Related: stackoverflow.com/q/52627575/1066234 Commented Jan 20, 2020 at 8:26

5 Answers 5

17

I would do this that way :

LoadScripts(); function LoadScripts(async) { if( async === undefined ) { async = false; } var scripts = []; var _scripts = ['jquery.min.js', 'bootstrap.min.js', 'plugins.js', 'main.js']; if(async){ LoadScriptsAsync(_scripts, scripts) }else{ LoadScriptsSync(_scripts,scripts) } } // what you are looking for : function LoadScriptsSync (_scripts, scripts) { var x = 0; var loopArray = function(_scripts, scripts) { // call itself loadScript(_scripts[x], scripts[x], function(){ // set x to next item x++; // any more items in array? if(x < _scripts.length) { loopArray(_scripts, scripts); } }); } loopArray(_scripts, scripts); } // async load as in your code function LoadScriptsAsync (_scripts, scripts){ for(var i = 0;i < _scripts.length;i++) { loadScript(_scripts[i], scripts[i], function(){}); } } // load script function with callback to handle synchronicity function loadScript( src, script, callback ){ script = document.createElement('script'); script.onerror = function() { // handling error when loading script alert('Error to handle') } script.onload = function(){ console.log(src + ' loaded ') callback(); } script.src = src; document.getElementsByTagName('head')[0].appendChild(script); } 
Sign up to request clarification or add additional context in comments.

Comments

2

You could do it with promises like this.

// loads an individual script var loadScript = function (path) { // generate promise return new Promise(function (fulfill, reject) { // create object var script = document.createElement('script'); // when it loads or the ready state changes script.onload = script.onreadystatechange = function () { // make sure it's finished, then fullfill the promise if (!this.readyState || this.readyState == 'complete') fulfill(this); }; // begin loading it script.src = path; // add to head document.getElementsByTagName('head')[0].appendChild(script); }); }; // this is the one you want var loadScripts = function (scripts) { return scripts.reduce( function (queue, path) { // once the current item on the queue has loaded, load the next one return queue.then(function () { // individual script return loadScript(path); }); }, Promise.resolve() /* this bit is so queue is always a promise */ ); }; 

Usage:

loadScripts(["foo.js", "bar.js"]).then(function () { // whatever you want to happen when it's all done }); 

It doesn't do any error handling though, so you'll have to implement that it if you need it.

1 Comment

I think second function name should be getScripts
1

Try this:

function loadscripts ( async ) { if( async === undefined ) { async = false; } var scripts = []; var _scripts = ['jquery.min.js', 'bootstrap.min.js', 'plugins.js', 'main.js']; for(var s in _scripts) { scripts[s] = document.createElement('script'); scripts[s].type = 'text/javascript'; scripts[s].src = _scripts[s]; scripts[s].async = async; } var loadNextScript = function() { var script = scripts.shift(); var loaded = false; document.getElementsByTagName('head').appendChild( script ); script.onload = script.onreadystatechange = function() { var rs = this.readyState; if (rs && rs != 'complete' && rs != 'loaded') return; if (loaded) return; loaded = true; if (scripts.length) { loadNextScript(); } else { // done } }; }; loadNextScript(); } 

4 Comments

isn't this "loadNextScript" function declaration supposed to be under the "for loop"?
@ZlatanO. No, loadNextScript is supposed to run "asynchronously", while for runs in a single, blocking way.
aha.. by this solution.. it firstly appends the scripts object, and then with loadNextScript(), puts them into a head tag - in the document DOM ?
This first creates the script elements. Then loadNextScript will add them to the dom, and call loadNextScript again after it loaded
1

Had to load scripts in given order x,y,z and since I only had a few of them. This approach worked for me. Could not load these in body or head since they are quite big and I'm using a static landing page.

document.addEventListener('DOMContentLoaded', function(event) { // initial DOM loaded var vendorJS = document.createElement('script'); vendorJS.src = 'assets/vendor.js'; var appJS = document.createElement('script'); appJS.src = 'assets/application.js'; var envJS = document.createElement('script'); envJS.src = 'assets/env.js'; document.body.appendChild(vendorJS); vendorJS.onload = vendorJS.onreadystatechange = function() { document.body.appendChild(appJS); appJS.onload = appJS.onreadystatechange = function() { document.body.appendChild(envJS); }; }; }); 

Comments

0

We can load one script after another in html by using lab.min.js.

This library run in Synchronous way.

<script> var _DIR_ = "js/vendor/"; $LAB.setOptions({ AlwaysPreserveOrder: true }); $LAB .queueScript(_DIR_ + 'jquery-v2-1-3.min.js') .queueWait() .queueScript(_DIR_ + 'angular.min.js') .queueWait() .queueScript(_DIR_ + 'socket.io-1.3.5.js') .queueScript(_DIR_ + 'angular-bootstrap/ui-bootstrap-tpls.min.js') .queueScript(_DIR_ + 'Angular plugins/angular-ui-notification.min.js') .runQueue(); </script> 

Comments