How to load recursively chained scripts with javascript?

Asked

Viewed 103 times

1

Hello, guys. I’m trying to do a function that works like the require of some languages, like Ruby. Use createElement after the page is already loaded is quiet, but chain and loading time is a tricky task.

With the document.write("<script src=" + ...) javascript does not even load, emit a warning stating that it cannot be used when scripts are being loaded asynchronously.

The complexity of my case is due to the fact that one script depends on another that is in another file, and this, in turn, depends on another, which is also in another file (chain request). I could solve everything by making a big file, but I’m very methodical with organization, and I feel really bad when I’m going to keep something in a huge file. Give him ctrl + f.

I don’t like having to use plugins for everything I do, so I eliminate dependencies (the more dependency, less knowledge, and less control of what happens behind the scenes), among other things. The requirejs is functional, but it uses callback to do the AMD (Asynchronous Module Definition), generating a semantic strangeness.

The also uses callback. The method .getScript ago XHR to get the script on the server, callback being the sure loading, which is also not my claim. What I intend to do is an alternative that is more akin to the conventional form of other languages. I don’t know if it’s possible, but suddenly use recursively the setTimeout not to let the lines after the require are interpreted, otherwise an error will be released, because the file on which the script depends would not yet be fully loaded, not existing yet Objeto to be extended.

Even more complex is to do this in chain, because the last file added, must be the first to be loaded, then the penultimate, and so on, until the subsequent lines of the first file, which triggers this chain reaction, continue to be interpreted. In which case no error would be raised, as nothing would be given as undefined.

  • 1

    Not in the pretense of dealing with the main problem, but if you have some server-side language you can do something similar to what I do in some projects. I have separate JS, but Gero in PHP a cluster in a file just to serve the client (you just add/change the desired JS in a list and it goes back).

  • 1

    @Bacco yes, my friend, I work with Ruby On Rails. He has something native to mount js in the order I need, all in one file only. Just use //= require .... This is a cool solution because the client will only make a request to upload the file. But I’m trying to do something generic, uncoupled.

  • I said more as a compliment. I think the question is good, and a good answer can be used for several situations where the dynamic load is interesting. Even to load polyfills only when necessary, in certain contexts.

  • I don’t know how it works in your project, but I use a minification tool, which combines several files into one. Couldn’t use some outside tool for your case?

  • @Pilati yes, my friend, it works, it would. Until I finish something I abstract as a server side language, this is exactly how I solve.

1 answer

1

Rafael, making this kind of management can be a little complicated, possibly we will miss some situation, etc.

In any case follows a small implementation:

//o primeiro argumento deveria ser a url do script, mas para este exemplo irei utilizar uma URL dinamica.
var Script = function (name, callback) {
  var self = this;
  self.name = name;
  self.callbacks = [];
  if (callback) {
    self.callbacks.push(callback);
  }

  // criando uma URL dinamica apartir do template
  self.source = document.getElementById(self.name).innerHTML;
  self.blob = new Blob([self.source], { type: "text/javascript" });
  self.url = URL.createObjectURL(self.blob);

  self.elem = document.createElement("script");
  self.elem.src = self.url;  
  self.elem.addEventListener("load", function () {
    self.callbacks.forEach(function (callback, indice) {
      callback(self);
    });
  });
  document.head.appendChild(self.elem);
}

Script.all = function(scripts, callback) {
  if (callback) {
    var complete = 0;
    var total = scripts.length;
    for (var indice = 0; indice < total; indice++) {
      scripts[indice].callbacks.push(function () {
        complete++;
        if (complete == total) {
          callback();
        }
      });
    }
  }
}

var then = function (script) { 
  console.log(script.name + " carregado"); 
};

var scripts = [];
scripts.push(new Script("script1", then));
scripts.push(new Script("script2", null));
scripts.push(new Script("script3", then));

Script.all(scripts, function () {
  console.log("scripts 1, 2 e 3 carregados");
  new Script("script4", then);
});
<template id="script1">
  console.log("script1");
</template>
<template id="script2">
  console.log("script2");
</template>
<template id="script3">
  console.log("script3");
</template>
<template id="script4">
  console.log("script4");
</template>

In the example above, I get a notification when the script1 and/or script3 are ready, regardless of the situation of the other scripts...

When the script1, the script2 and the script3 are ready, so add the script4... i.e., the script4 is dependent on script1, the script2 and the script3.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.