Skip to content

Instantly share code, notes, and snippets.

@nickclaw
Created December 9, 2014 00:44
Show Gist options
  • Save nickclaw/965e292e05ddbf4f1296 to your computer and use it in GitHub Desktop.
Save nickclaw/965e292e05ddbf4f1296 to your computer and use it in GitHub Desktop.
loader.js
/**
* Loader
*/
(function() {
var cache = {};
/**
* Initialize loader
* Looks for init-script tag and starts the loading process
*/
window.addEventListener('load', function onReady() {
window.removeEventListener('load', onReady);
var script = document.querySelector('script[data-src][data-loader]');
loadScript(script.getAttribute('data-src'));
});
/**
* Reprents a single file and it's corresponding data
* @constructor
* @extends {Promise}
* @param {string} name
* @param {Array.<string>} requirements
* @param {Function} factory
*/
function Module(name, requirements, factory) {
this.name = name;
this.path = name + '.js';
this.requires = requirements;
var self = this;
Promise.call(this, function(res, rej) {
var required = requirements.map(require);
Promise.all(required).then(function(modules) {
try {
res(factory.apply(self, modules));
} catch (e) {
rej(e);
}
});
});
}
Module.prototype = Object.create(Promise.prototype);
Module.prototype.require = require;
Module.prototype.has = function(name) {
return !!cache[name];
};
/**
* Get a defined script by name
* {string} name
* @return {Promise}
*/
function require(name) {
if (cache[name]) return cache[name];
return loadScript(name).then(function() {
return cache[name];
});
}
/**
* Loads a script asynchronously
* @param {string} name - unnormalized
* @return {Promise}
*/
function loadScript(name) {
var path = name + '.js';
return new Promise(function(res, rej) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.src = path;
script.setAttribute('data-name', name);
document.head.appendChild(script);
script.onerror = rej;
script.onload = res;
});
}
//
// Public functions
//
var defined = {};
/**
* Define a class and inject requirements
*/
window.define = function define(requirements, factory) {
// TODO check for one define call
var name = document.currentScript.getAttribute('data-name');
// only allow one define call per path
if (defined[name]) {
throw new Error("Object already defined under same path: '" + name + "'");
} else {
defined[name] = true;
}
/**
* return the module to the define call
* this lets people handle the resulting promise. e.g.
*
* define([], function() {
*
* }).catch(function(err) {
* document.write('there was an error.');
* });
*/
return cache[name] = new Module(name, requirements, factory);
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment