-
Notifications
You must be signed in to change notification settings - Fork 7
Script loading
The present project makes a certain number of demands from its script loading. Because some types employ inheritance, e.g. Architect isa Character (architect.js extends character.js), by necessity, character.js must be loaded before architect.js lest architect attempt to extend undefined. Additionally, if an error occurs in any javascript file, it is integral that such issues be visible via debuggers, lest the programmers not know what is failing or why. To meet one requirement or the other is a trivial task, but to meet both together required additional research. As such, we have two main issues to tackle in our script loading:
- Javascript imports that load in a predefined, linear, synchronous order to support base2 inheritance
- Javascript imports that are debuggable via browser consoles
With these objectives in mind, the first attempts at resolution centered upon preexisting libraries that might accomplish both--so, the following was tried:
- jQuery's $.getScript(): The most immediate resource available was jQuery, as it had already been employed elsewhere in the project. Exploration of its documentation revealed a $.getScript() method, which takes in a script path and imports it. While this was indeed the synchronous solution we were after, it accomplishes such in a manner that hides the scripts from debuggers, meaning that if any one file caused an error, it would not be displayed. Indeed, though this may be the ideal solution for when everything is said and done, it is not the ideal solution for debugging during the early project stages... not even close to ideal... probably more near the "silly" end of the spectrum.
- RequireJS: This lead appeared to be a promising one, but again left one of our requirements unsatisfied. Coupled with our reluctance to append yet another library to our growing list (especially for such a seemingly simply task), RequireJS failed to load the scripts synchronously, even though it succeeded in revealing the scripts to the debugger. As such we needed to look elsewhere for the solution.
When it appears that the solution may not already exist prepackaged, obviously the next step is to consult the hivemind. Google, Reddit, and Stack Overflow were equally scoured for a solution from someone else having the same issue, but none matched quite closely enough to our scenario in order to successfully implement their suggestions (many were tried).
It seemed that we were left to our own devices...
The solution was found from a closer examination of scripts and their properties. Apparently, scripts have an .onload aspect that can be set to a callback only after they have finished loading entirely. The single detriment is a certain instability in Internet Explorer, which doesn't always call the .onload handler when it is supposed to (oh no... not internet explorer -_- ). As such, the following include function was implemented:
var include = {
// Array containing all necessary imports
directories: [],
// Number of imports needed to be handled, plus a counter, n
numberOfImports: 0,
n: 0,
// Helper function to append the scripts (call once at start)
run: function () {
// Only import when there are more to go
if (n < numberOfImports) {
var script = document.createElement("script");
script.setAttribute("src", directories[n]);
script.onload = include.run;
document.getElementsByTagName("head")[0].appendChild(script);
n++;
}
},
includeInit: function (d) {
directories = d;
numberOfImports = directories.length;
n = 0;
include.run();
}
}
The include script employs the following algorithm:
- Take in a list of directories, d, the see how many imports need to be parsed based on d.length
- Start the first import in the list, checking to make sure that n (the number of scripts so far loaded) does not exceed numberOfImports (the total number that have to be loaded--otherwise, we will overshoot the array bounds
- Set up the script tag for the calling html document, but not before the integral piece of code: script.onload = include.run; This will call include.run only after the present script has finished loading, and progress the inclusion to the next path listed in the directories array
- Rinse, repeat until all imports have been resolved!
Elegant in its simplicity.