Skip to content

Instantly share code, notes, and snippets.

@jsmaker
Created November 2, 2012 03:16
Show Gist options
  • Save jsmaker/3998516 to your computer and use it in GitHub Desktop.
Save jsmaker/3998516 to your computer and use it in GitHub Desktop.
defined.js fast and small AMD loader
var defined = function (setup) {
'use strict';
setup.symble = setup.symble || 'define';
/////////////healpers//////////////
[].indexOf||(Array.prototype.indexOf=function(a,b,c){for(c=this.length,b=(c+~~b)%c;b<c&&(!(b in this)||this[b]!==a);b++);return b^c?b:-1;});
[].filter ||(Array.prototype.filter = function(fn, thisp) { if (this === null) throw new TypeError; if (typeof fn !== "function") throw new TypeError; var result = []; for (var i = 0; i < this.length; i++){if (i in this) {var val = this[i]; if (fn.call(thisp, val, i, this)){result.push(val);}}} return result;});
[].map||(Array.prototype.map=function(a){for(var b=this,c=b.length,d=[],e=0,f;e<b;)d[e]=e in b?a.call(arguments[1],b[e],e++,b):f;return d});
var xmlHTTPObject = (function getXMLHTTPObject(){var e=[function(){return new XMLHttpRequest},function(){return new ActiveXObject("Msxml2.XMLHTTP")},function(){return new ActiveXObject("Msxml3.XMLHTTP")},function(){return new ActiveXObject("Microsoft.XMLHTTP")}],t=!1;for(var n=0;n<e.length;n++){try{return t=e[n],t(),t}catch(r){continue}break}return t})();
////////////loader functions///////////
function Mod(name, dependencies, constructor, resolvedData, resolved, allLoaded){
this.name = name || undefined;
this.dependencies = dependencies || [];
this.constructor = constructor || function (){};
this.resolvedData = resolvedData || null;
this.resolved = resolved || false;
this.allLoaded = allLoaded || false;
this.loadedDeps = new Array(this.dependencies.length);
}
function defineLoaderSymble(defineSymb, onDefine) {
function constructorOnly(constructor) {
return new Mod(null, null, constructor);;
}
function constructorDepndecies(dependencies, constructor) {
if (typeof dependencies === 'string') {
return new Mod(dependencies, null, constructor);
}else{
return new Mod(null, dependencies, constructor);
}
}
function constructorDepndeciesName(name, dependencies, constructor) {
return new Mod(name, dependencies, constructor);
}
var argSwitch = [constructorOnly, constructorDepndecies, constructorDepndeciesName];
function define(name, dependencies, constructor) {
var aLength = arguments.length;
onDefine(argSwitch[aLength - 1].apply(null, arguments));
}
window[defineSymb] = define;
}
function loadMain(script, cb) {
if (!script) {
var d = 'data-'+setup.symble+'-main';
var n = document.querySelector('['+d+']');
script = n && n.getAttribute(d);
}
script && define('defined',[script],function(){return function(){return F;};});
}
function load(url, callback) {
if (loadedViaCSS(url, callback)) {return;}
if (loadedViaAjax(url, callback)) {return;}
if (loadedViaScript(url, callback)) {return;}
}
function loadedViaCSS(url, callback) {
if (url.indexOf('css!') === 0) {
url = url.substr(4, url.length);
url = setup.base ? setup.base + url : url;
var link = document.createElement("link");
link.href = url;
link.setAttribute('rel', 'stylesheet');
appendToHead(link);
callback && callback(link);
return true;
}
}
function loadedViaAjax(url, callback) {
if (url.indexOf('load!') === 0) {
url = url.substr(5, url.length);
url = setup.base ? setup.base + url : url;
requestUrl(url, function(req) {
callback && callback(req.responseText);
});
return true;
}
}
function finishScriptLoad(url, callback){
return function(){
removeScriptFromSQ();
F[cleanUrl(url)] = arguments;
callback.apply(this, arguments);
}
}
function loadedViaScript(url, callback) {
url += ~url.indexOf('.js') ? '' : '.js';
url = url.indexOf('js!') === 0 ? url.substr(3) : url;
if (url.indexOf('order!') === 0) {
url = url.substr(6);
if (addToScriptSQ(url, callback)) {
return true;
} else {
S.busy = true;
callback = finishScriptLoad(url, callback);
}
}
loadScript(url, callback);
return true;
}
function loadScript(url, callback) {
var script = document.createElement("script");
script.type = "text/javascript";
//script.async = true;
if (script.readyState) { //IE
// script.onreadystatechange = function() {
// console.log('script.readyState '+script.readyState );
// if (script.readyState == "loaded" || script.readyState == "complete") {
// //console.log(script.src);
// // script.onreadystatechange = null;
// callback && callback(script);
// }
// };
loadedViaAjax('load!'+url, function(data){
//eval(data);
script.textContent = data;
appendToHead(script);
callback && callback(script);
});
return;
} else { //Others
script.onload = function() {
script.onload = null;
callback && callback(script);
};
script.onerror = function(e){
script.onerror = null;
//script.parentNode.removeChild(script);
callback && callback(script);
return false;
}
}
url = setup.base ? setup.base + url : url;
script.src = url;
appendToHead(script);
}
function cleanUrl(dependency_url){
return dependency_url.split('!').pop();
}
function loadAMDDependencies(mod) {
if (mod.loaded===mod.dependencies.length) {return};
mod.loaded = 0;
mod.dependencies.forEach(function(url) {
var dependency_url = cleanUrl(url);
if (Q.filter(function (url) {return url === dependency_url}).length) {
return mod.loaded++;
}
Q.push(dependency_url);
load(url, function(data) {
if (isPlugin(url)) {
L.unshift(new Mod(dependency_url, null, null, data, true, true));
} else {
//give the module his name
if (!L[L.length - 1].name) {
L[L.length - 1].name = dependency_url;
}
}
mod.loaded++;
});
});
}
function resolveAMD(mod) {
if (mod === true) { return mod;}
if (mod.resolved) { return mod.resolvedData;}
var modules = null;
if (mod.loadedDeps) {
modules = mod.loadedDeps.map(resolveAMD);
}
mod.resolved = true;
return F[mod.name] = mod.resolvedData = mod.constructor.apply(null, modules);
}
function requestUrl(url, cb) {
var req = xmlHTTPObject();
req.open('GET', url, true);
req.onreadystatechange = function() {
if (req.readyState == 4) {
if (req.status != 200 && req.status != 304) {
cb && cb('HTTP error ' + req.status);
} else {
cb && cb(req);
}
}
};
req.send();
}
function isReady(mod) {
var dependency;
if (mod.dependencies.length === 0 || mod.allLoaded) {
return mod.allLoaded = true;
}
var modD = mod.dependencies;
if (mod.loaded === modD.length) {
for (var i = modD.length; i--;) {
dependency = inArray(L, byName.bind(null, cleanUrl(modD[i])));
if (!dependency || !isReady(dependency)) {
clearTimeout(timeoutTicket);
timeoutTicket = setTimeout(testForLoaded, 20);
return false;
}
mod.loadedDeps[i] = dependency;
}
return mod.allLoaded = true;
}
clearTimeout(timeoutTicket);
timeoutTicket = setTimeout(testForLoaded, 20);
return false;
}
function addToScriptSQ(url, callback) {
return S.busy && S.push({
url: url,
callback: callback
});
}
function removeScriptFromSQ() {
var qItem = S.shift();
S.busy = !!S.length;
if (!qItem) {return;}
loadScript(qItem.url, finishScriptLoad(qItem.url,qItem.callback));
}
function inArray(arr, test) {
var item;
for (var i = 0; i < arr.length; i++) {
item = arr[i];
if (test(item)) {
return item;
}
}
return null;
}
function isPlugin(dependency_url) {
if (dependency_url.split('!').length > 1) { return true;}
}
function appendToHead(el) {
document.getElementsByTagName("head")[0].appendChild(el);
}
function byName(name, item) {
return item.name === name;
}
function testForLoaded() {
L.filter(isReady).forEach(resolveAMD);
}
////////////loader main/////////////
var Q = [];//loading Q
var S = [];//scriptStack
var L = [];//loaded
var F = {};//finished
var timeoutTicket;
defineLoaderSymble(setup.symble, function(mod) {
if (mod.name) {
Q.push(mod.name);
L.unshift(mod);
} else {
L.push(mod);
}
loadAMDDependencies(mod);
clearTimeout(timeoutTicket);
timeoutTicket = setTimeout(testForLoaded, 150);
});
setup.loadMain && loadMain();
return {
loadMain:loadMain,
testForLoaded:testForLoaded,
isReady:isReady,
Q: Q, S:S, L:L, F:F };
}
_defined = defined({
loadMain:true,
base:''
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment