Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add script tags and load scripts sequentially

Tags:

javascript

I have the following function that loads a given script :

function addScriptTag(url){
  var script = document.createElement('script');
  script.src = url;
  document.getElementsByTagName('head')[0].appendChild(script);
}

I used the function to load libs correlated to each other where lib2 depends on lib1 and lib1 depends on jquery :

function loadThemAll(){
  addScriptTag('http://path/to/jquery.js');
  addScriptTag('http://path/to/lib1.js');
  addScriptTag('http://path/to/lib2.js');
}

The problem is that even in that order, when lib1 needs jQuery, it doesn't find it. The same applies for lib2 that uses lib1.

How can I make script tag creates and load the script sequentially ? In other words :

add script tag for jQuery and load it.

When jQuery is loaded, add script tag for lib1 and load it.

When lib1 is loaded, add script tag for lib2 and load it.

like image 983
odb17237 Avatar asked Aug 26 '19 22:08

odb17237


2 Answers

You aren't waiting for the previous script to load before attempting to load the next one, you could try using Promises and the onload callback of the script elements.

function addScriptTag(url) {
  return new Promise(function (resolve, reject) {
    var script = document.createElement('script');
    script.onload = resolve;
    script.onerror = reject;
    script.src = url;
    document.getElementsByTagName('head')[0].appendChild(script);
  })
}

addScriptTag('http://path/to/jquery.js').then(function() {
  return addScriptTag('http://path/to/lib1.js');
}).then(function() {
  return addScriptTag('http://path/to/lib2.js');
});

Since the onload method of the new script is set to the resolve of the returned Promise of addScriptTag this should cause the scripts to wait until the previous one was loaded.

You could take it a step further and write a function that takes a list of scripts to load sequentially:

function loadScripts(scripts, promise) {
  if (!promise) {
    promise = new Promise();
  }

  script = scripts.shift();
  if (script) {
    addScriptTag(script).then(function () {
      loadScripts(scripts, promise);
    }).catch(function () {
      promise.reject();
    });
  } else {
    promise.resolve();
  }

  return promise;
}

loadScripts([
  'http://path/to/jquery.js',
  'http://path/to/lib1.js', 
  'http://path/to/lib2.js'
]).then(function () {
  console.log("Scripts loaded");
});
like image 178
Victor Babel Avatar answered Sep 25 '22 01:09

Victor Babel


Have addScriptTag return a Promise that resolves when the script is loaded, and await each call:

function addScriptTag(url){
  return new Promise((resolve, reject) => {
    var script = document.createElement('script');
    script.addEventListener('load', resolve);
    script.addEventListener('error', reject);
    script.src = url;
    document.head.appendChild(script);
  });
}


async function loadThemAll(){
  await addScriptTag('http://path/to/jquery.js');
  await addScriptTag('http://path/to/lib1.js');
  await addScriptTag('http://path/to/lib2.js');
}

loadThemAll()
  .then(() => {
    console.log('Everything is loaded!');
  })
  .catch((err) => {
    console.log('There was a problem:', err);
  });

You can also use async=false, but this will block until the script loads, so may not be a great idea:

function addScriptTag(url){
  var script = document.createElement('script');
  script.setAttribute('async', 'false');
  script.src = url;
  document.head.appendChild(script);
}


function loadThemAll(){
  addScriptTag('http://path/to/jquery.js');
  addScriptTag('http://path/to/lib1.js');
  addScriptTag('http://path/to/lib2.js');
}
like image 33
CertainPerformance Avatar answered Sep 25 '22 01:09

CertainPerformance