Created
November 2, 2012 03:16
-
-
Save jsmaker/3998516 to your computer and use it in GitHub Desktop.
defined.js fast and small AMD loader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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