├── README ├── do.js ├── do.min.js └── test ├── a1.js ├── a2.js ├── a3.js ├── a4.js ├── a5.js ├── core.js └── index.html /README: -------------------------------------------------------------------------------- 1 | ________ 2 | ___ __ \_____ 3 | __ / / / __ \ 4 | _ /_/ // /_/ / 5 | /_____/ \____/ v 2.0 pre 6 | 7 | Do是一个很轻量文件加载和依赖关系管理的库。目前do.min.js(4.6k)。可能灵活的组织开发中的JS/CSS模块文件,定制各种加载策略。 8 | 9 | 具体使用方法: http://kejun.github.com/Do/ 10 | 11 | -------------------------------------------------------------------------------- /do.js: -------------------------------------------------------------------------------- 1 | /* Do version 2.0 pre 2 | * creator: kejun (listenpro@gmail.com) 3 | * 最新更新:2011-7-12 4 | */ 5 | 6 | (function(win, doc) { 7 | 8 | // 已加载模块 9 | var loaded = {}, 10 | 11 | // 已加载列表 12 | loadList = {}, 13 | 14 | // 加载中的模块 15 | loadingFiles = {}, 16 | 17 | // 内部配置文件 18 | config = { 19 | // 是否自动加载核心库 20 | autoLoad: true, 21 | 22 | // 加载延迟 23 | timeout: 6000, 24 | 25 | // 核心库 26 | coreLib: ['http://t.douban.com/js/jquery.min.js'], 27 | 28 | /* 模块依赖 29 | * { 30 | * moduleName: { 31 | * path: 'URL', 32 | * type:'js|css', 33 | * requires:['moduleName1', 'fileURL'] 34 | * } 35 | * } 36 | */ 37 | mods: {} 38 | }, 39 | 40 | jsSelf = (function() { 41 | var files = doc.getElementsByTagName('script'); 42 | return files[files.length - 1]; 43 | })(), 44 | 45 | // 全局模块 46 | globalList = [], 47 | 48 | // 外部参数 49 | extConfig, 50 | 51 | // domready回调堆栈 52 | readyList = [], 53 | 54 | // DOM Ready 55 | isReady = false, 56 | 57 | // 模块间的公共数据 58 | publicData = {}, 59 | 60 | // 公共数据回调堆栈 61 | publicDataStack = {}, 62 | 63 | isArray = function(e) { 64 | return e.constructor === Array; 65 | }, 66 | 67 | getMod = function(e) { 68 | var mods = config.mods, mod; 69 | if (typeof e === 'string') { 70 | mod = (mods[e])? mods[e] : { path: e }; 71 | } else { 72 | mod = e; 73 | } 74 | return mod; 75 | }, 76 | 77 | load = function(url, type, charset, cb) { 78 | var wait, n, t, img, 79 | 80 | done = function() { 81 | loaded[url] = 1; 82 | cb && cb(url); 83 | cb = null; 84 | win.clearTimeout(wait); 85 | }; 86 | 87 | if (!url) { 88 | return; 89 | } 90 | 91 | if (loaded[url]) { 92 | loadingFiles[url] = false; 93 | if (cb) { 94 | cb(url); 95 | } 96 | return; 97 | } 98 | 99 | if (loadingFiles[url]) { 100 | setTimeout(function() { 101 | load(url, type, charset, cb); 102 | }, 10); 103 | return; 104 | } 105 | 106 | loadingFiles[url] = true; 107 | 108 | wait = win.setTimeout(function() { 109 | /* 目前延时回调处理,超时后如果有延时回调,执行回调,然后继续等 110 | * 延时回调的意义是log延时长的URI,这个处理不属于加载器本身的功能移到外部 111 | * 没有跳过是为了避免错误。 112 | */ 113 | if (config.timeoutCallback) { 114 | try { 115 | config.timeoutCallback(url); 116 | } catch(ex) {} 117 | } 118 | }, config.timeout); 119 | 120 | t = type || url.toLowerCase().split(/\./).pop().replace(/[\?#].*/, ''); 121 | 122 | if (t === 'js') { 123 | n = doc.createElement('script'); 124 | n.setAttribute('type', 'text/javascript'); 125 | n.setAttribute('src', url); 126 | n.setAttribute('async', true); 127 | } else if (t === 'css') { 128 | n = doc.createElement('link'); 129 | n.setAttribute('type', 'text/css'); 130 | n.setAttribute('rel', 'stylesheet'); 131 | n.setAttribute('href', url); 132 | } 133 | 134 | if (charset) { 135 | n.charset = charset; 136 | } 137 | 138 | if (t === 'css') { 139 | img = new Image(); 140 | img.onerror = function() { 141 | done(); 142 | img.onerror = null; 143 | img = null; 144 | } 145 | img.src = url; 146 | } else { 147 | // firefox, safari, chrome, ie9下加载失败触发 148 | // 如果文件是404, 会比timeout早触发onerror。目前不处理404,只处理超时 149 | n.onerror = function() { 150 | done(); 151 | n.onerror = null; 152 | }; 153 | 154 | // ie6~8通过创建vbscript可以识别是否加载成功。 155 | // 但这样需先测试性加载再加载影响性能。即使没成功加载而触发cb,顶多报错,没必要杜绝这种报错 156 | 157 | // ie6~9下加载成功或失败,firefox, safari, opera下加载成功触发 158 | n.onload = n.onreadystatechange = function() { 159 | var url; 160 | if (!this.readyState || 161 | this.readyState === 'loaded' || 162 | this.readyState === 'complete') { 163 | done(); 164 | n.onload = n.onreadystatechange = null; 165 | } 166 | }; 167 | } 168 | 169 | jsSelf.parentNode.insertBefore(n, jsSelf); 170 | }, 171 | 172 | // 加载依赖论文件(顺序) 173 | loadDeps = function(deps, cb) { 174 | var mods = config.mods, 175 | id, m, mod, i = 0, len; 176 | 177 | id = deps.join(''); 178 | len = deps.length; 179 | 180 | if (loadList[id]) { 181 | cb(); 182 | return; 183 | } 184 | 185 | function callback() { 186 | if(!--len) { 187 | loadList[id] = 1; 188 | cb(); 189 | } 190 | } 191 | 192 | for (; m = deps[i++]; ) { 193 | mod = getMod(m); 194 | if (mod.requires) { 195 | loadDeps(mod.requires, (function(mod){ 196 | return function(){ 197 | load(mod.path, mod.type, mod.charset, callback); 198 | }; 199 | })(mod)); 200 | } else { 201 | load(mod.path, mod.type, mod.charset, callback); 202 | } 203 | } 204 | }, 205 | 206 | /*! 207 | * contentloaded.js 208 | * 209 | * Author: Diego Perini (diego.perini at gmail.com) 210 | * Summary: cross-browser wrapper for DOMContentLoaded 211 | * Updated: 20101020 212 | * License: MIT 213 | * Version: 1.2 214 | * 215 | * URL: 216 | * http://javascript.nwbox.com/ContentLoaded/ 217 | * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE 218 | * 219 | */ 220 | 221 | // @win window reference 222 | // @fn function reference 223 | contentLoaded = function(fn) { 224 | var done = false, top = true, 225 | doc = win.document, 226 | root = doc.documentElement, 227 | add = doc.addEventListener ? 'addEventListener' : 'attachEvent', 228 | rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent', 229 | pre = doc.addEventListener ? '' : 'on', 230 | 231 | init = function(e) { 232 | if (e.type == 'readystatechange' && doc.readyState != 'complete') return; 233 | (e.type == 'load' ? win : doc)[rem](pre + e.type, init, false); 234 | if (!done && (done = true)) fn.call(win, e.type || e); 235 | }, 236 | 237 | poll = function() { 238 | try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; } 239 | init('poll'); 240 | }; 241 | 242 | if (doc.readyState == 'complete') fn.call(win, 'lazy'); 243 | else { 244 | if (doc.createEventObject && root.doScroll) { 245 | try { top = !win.frameElement; } catch(e) { } 246 | if (top) { 247 | poll(); 248 | } 249 | } 250 | doc[add](pre + 'DOMContentLoaded', init, false); 251 | doc[add](pre + 'readystatechange', init, false); 252 | win[add](pre + 'load', init, false); 253 | } 254 | }, 255 | 256 | fireReadyList = function() { 257 | var i = 0, list; 258 | if (readyList.length) { 259 | for(; list = readyList[i++]; ) { 260 | d.apply(this, list); 261 | } 262 | } 263 | }, 264 | 265 | d = function() { 266 | var args = [].slice.call(arguments), fn, id; 267 | 268 | // 加载核心库 269 | if (config.autoLoad && 270 | !loadList[config.coreLib.join('')]) { 271 | loadDeps(config.coreLib, function(){ 272 | d.apply(null, args); 273 | }); 274 | return; 275 | } 276 | 277 | // 加载全局库 278 | if (globalList.length > 0 && 279 | !loadList[globalList.join('')]) { 280 | loadDeps(globalList, function(){ 281 | d.apply(null, args); 282 | }); 283 | return; 284 | } 285 | 286 | if (typeof args[args.length - 1] === 'function' ) { 287 | fn = args.pop(); 288 | } 289 | 290 | id = args.join(''); 291 | 292 | if ((args.length === 0 || loadList[id]) && fn) { 293 | fn(); 294 | return; 295 | } 296 | 297 | loadDeps(args, function() { 298 | loadList[id] = 1; 299 | fn && fn(); 300 | }); 301 | }; 302 | 303 | d.add = function(sName, oConfig) { 304 | if (!sName || !oConfig || !oConfig.path) { 305 | return; 306 | } 307 | config.mods[sName] = oConfig; 308 | }; 309 | 310 | d.delay = function() { 311 | var args = [].slice.call(arguments), delay = args.shift(); 312 | win.setTimeout(function() { 313 | d.apply(this, args); 314 | }, delay); 315 | }; 316 | 317 | d.global = function() { 318 | var args = isArray(arguments[0])? arguments[0] : [].slice.call(arguments); 319 | globalList = globalList.concat(args); 320 | }; 321 | 322 | d.ready = function() { 323 | var args = [].slice.call(arguments); 324 | if (isReady) { 325 | return d.apply(this, args); 326 | } 327 | readyList.push(args); 328 | }; 329 | 330 | d.css = function(s) { 331 | var css = doc.getElementById('do-inline-css'); 332 | if (!css) { 333 | css = doc.createElement('style'); 334 | css.type = 'text/css'; 335 | css.id = 'do-inline-css'; 336 | jsSelf.parentNode.insertBefore(css, jsSelf); 337 | } 338 | 339 | if (css.styleSheet) { 340 | css.styleSheet.cssText = css.styleSheet.cssText + s; 341 | } else { 342 | css.appendChild(doc.createTextNode(s)); 343 | } 344 | }; 345 | 346 | d.setData = d.setPublicData = function(prop, value) { 347 | var cbStack = publicDataStack[prop]; 348 | 349 | publicData[prop] = value; 350 | 351 | if (!cbStack) { 352 | return; 353 | } 354 | 355 | while (cbStack.length > 0) { 356 | (cbStack.pop()).call(this, value); 357 | } 358 | }; 359 | 360 | d.getData = d.getPublicData = function(prop, cb) { 361 | if (publicData[prop]) { 362 | cb(publicData[prop]); 363 | return; 364 | } 365 | 366 | if (!publicDataStack[prop]) { 367 | publicDataStack[prop] = []; 368 | } 369 | 370 | publicDataStack[prop].push(function(value){ 371 | cb(value); 372 | }); 373 | }; 374 | 375 | d.setConfig = function(n, v) { 376 | config[n] = v; 377 | return d; 378 | }; 379 | 380 | d.getConfig = function(n) { 381 | return config[n]; 382 | }; 383 | 384 | win.Do = d; 385 | 386 | contentLoaded(function() { 387 | isReady = true; 388 | fireReadyList(); 389 | }); 390 | 391 | // 初始外部配置 392 | extConfig = jsSelf.getAttribute('data-cfg-autoload'); 393 | if (extConfig) { 394 | config.autoLoad = (extConfig.toLowerCase() === 'true') ? true : false; 395 | } 396 | 397 | extConfig = jsSelf.getAttribute('data-cfg-corelib'); 398 | if (extConfig) { 399 | config.coreLib = extConfig.split(','); 400 | } 401 | 402 | })(window, document); 403 | -------------------------------------------------------------------------------- /do.min.js: -------------------------------------------------------------------------------- 1 | /* Do version 2.0 pre 2 | * creator: kejun (listenpro@gmail.com) 3 | * 最新更新:2011-7-12 4 | */(function(a,b){var c={},d={},e={},f={autoLoad:!0,timeout:6e3,coreLib:["http://t.douban.com/js/jquery.min.js"],mods:{}},g=function(){var a=b.getElementsByTagName("script");return a[a.length-1]}(),h=[],i,j=[],k=!1,l={},m={},n=function(a){return a.constructor===Array},o=function(a){var b=f.mods,c;typeof a=="string"?c=b[a]?b[a]:{path:a}:c=a;return c},p=function(d,h,i,j){var k,l,m,n,o=function(){c[d]=1,j&&j(d),j=null,a.clearTimeout(k)};if(!!d){if(c[d]){e[d]=!1,j&&j(d);return}if(e[d]){setTimeout(function(){p(d,h,i,j)},10);return}e[d]=!0,k=a.setTimeout(function(){if(f.timeoutCallback)try{f.timeoutCallback(d)}catch(a){}},f.timeout),m=h||d.toLowerCase().substring(d.lastIndexOf(".")+1),m==="js"?(l=b.createElement("script"),l.setAttribute("type","text/javascript"),l.setAttribute("src",d),l.setAttribute("async",!0)):m==="css"&&(l=b.createElement("link"),l.setAttribute("type","text/css"),l.setAttribute("rel","stylesheet"),l.setAttribute("href",d)),i&&(l.charset=i),m==="css"?(n=new Image,n.onerror=function(){o(),n.onerror=null,n=null},n.src=d):(l.onerror=function(){o(),l.onerror=null},l.onload=l.onreadystatechange=function(){var a;if(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")o(),l.onload=l.onreadystatechange=null}),g.parentNode.insertBefore(l,g)}},q=function(a,b){function k(){--j||(d[e]=1,b())}var c=f.mods,e,g,h,i=0,j;e=a.join(""),j=a.length;if(d[e])b();else for(;g=a[i++];)h=o(g),h.requires?q(h.requires,function(a){return function(){p(a.path,a.type,a.charset,k)}}(h)):p(h.path,h.type,h.charset,k)},r=function(b){var c=!1,d=!0,e=a.document,f=e.documentElement,g=e.addEventListener?"addEventListener":"attachEvent",h=e.addEventListener?"removeEventListener":"detachEvent",i=e.addEventListener?"":"on",j=function(d){if(d.type!="readystatechange"||e.readyState=="complete")(d.type=="load"?a:e)[h](i+d.type,j,!1),!c&&(c=!0)&&b.call(a,d.type||d)},k=function(){try{f.doScroll("left")}catch(a){setTimeout(k,50);return}j("poll")};if(e.readyState=="complete")b.call(a,"lazy");else{if(e.createEventObject&&f.doScroll){try{d=!a.frameElement}catch(l){}d&&k()}e[g](i+"DOMContentLoaded",j,!1),e[g](i+"readystatechange",j,!1),a[g](i+"load",j,!1)}},s=function(){var a=0,b;if(j.length)for(;b=j[a++];)t.apply(this,b)},t=function(){var a=[].slice.call(arguments),b,c;if(f.autoLoad&&!d[f.coreLib.join("")])q(f.coreLib,function(){t.apply(null,a)});else{if(h.length>0&&!d[h.join("")]){q(h,function(){t.apply(null,a)});return}typeof a[a.length-1]=="function"&&(b=a.pop()),c=a.join("");if((a.length===0||d[c])&&b){b();return}q(a,function(){d[c]=1,b&&b()})}};t.add=function(a,b){!a||!b||!b.path||(f.mods[a]=b)},t.delay=function(){var b=[].slice.call(arguments),c=b.shift();a.setTimeout(function(){t.apply(this,b)},c)},t.global=function(){var a=n(arguments[0])?arguments[0]:[].slice.call(arguments);h=h.concat(a)},t.ready=function(){var a=[].slice.call(arguments);if(k)return t.apply(this,a);j.push(a)},t.css=function(a){var c=b.getElementById("do-inline-css");c||(c=b.createElement("style"),c.type="text/css",c.id="do-inline-css",g.parentNode.insertBefore(c,g)),c.styleSheet?c.styleSheet.cssText=c.styleSheet.cssText+a:c.appendChild(b.createTextNode(a))},t.setData=t.setPublicData=function(a,b){var c=m[a];l[a]=b;if(!!c)while(c.length>0)c.pop().call(this,b)},t.getData=t.getPublicData=function(a,b){l[a]?b(l[a]):(m[a]||(m[a]=[]),m[a].push(function(a){b(a)}))},t.setConfig=function(a,b){f[a]=b;return t},t.getConfig=function(a){return f[a]},a.Do=t,r(function(){k=!0,s()}),i=g.getAttribute("data-cfg-autoload"),i&&(f.autoLoad=i.toLowerCase()==="true"?!0:!1),i=g.getAttribute("data-cfg-corelib"),i&&(f.coreLib=i.split(","))})(window,document) -------------------------------------------------------------------------------- /test/a1.js: -------------------------------------------------------------------------------- 1 | var a1 = 1; 2 | -------------------------------------------------------------------------------- /test/a2.js: -------------------------------------------------------------------------------- 1 | var a2 = 2; 2 | -------------------------------------------------------------------------------- /test/a3.js: -------------------------------------------------------------------------------- 1 | var a3 = 3; 2 | -------------------------------------------------------------------------------- /test/a4.js: -------------------------------------------------------------------------------- 1 | var a4 = 4; 2 | -------------------------------------------------------------------------------- /test/a5.js: -------------------------------------------------------------------------------- 1 | var a5 = 5; 2 | -------------------------------------------------------------------------------- /test/core.js: -------------------------------------------------------------------------------- 1 | var core_lib_loaded = 1; 2 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |