javascript实现模块加载器

实现思路来自于网上资料,自己做了一些修改,仅供学习。

window.ISF = (function(win, doc) {
	Array.prototype.remove = function() {
        var items = arguments, 
            k = 0, 
            len = items.length, 
            item = null;
            
        for (; k < len; k++) {
            item = items[k];
            for (var i = 0, n = 0; i < this.length; i++) {
                if (this[i] != item) {
                    this[n++] = this[i];
                }
            }
            this.length = n;
        }
        return this;
    };
    
	var moduleCache = {},
		head = doc.head;
	
	function Mod(config){
		this.handlers = {}; 
		this.oneTimeHandlers = {}; 
		
		this.modName = config.modName;
		this.status =  config.status;
		this.export = config.export;
		
		
		this.on = function(type, handler){
			this.handlers[type] = this.handlers[type] || [];
			this.handlers[type].push(handler);
			return this;
		};
		
		this.off = function(type, handler){
			if(this.handlers[type]){
				this.handlers[type].remove(handler);
			}
			if(this.oneTimeHandlers[type]){
				this.oneTimeHandlers[type].remove(handler);
			}
			return this;
		};
		
		this.one = function(type, handler){
			this.oneTimeHandlers[type] = this.oneTimeHandlers[type] || [];
			this.oneTimeHandlers[type].push(handler);
			return this;
		}; 
		
		this.fire = function(){
			var eventResults = [],
				type = arguments[0],
				args = Array.prototype.slice.call(arguments, 1),
			   _handlers = this.handlers[type],
			   _oneTimeHandlers = this.oneTimeHandlers[type],
			   _oneTimeHandlersLen = _oneTimeHandlers.length;
			if(_handlers && _handlers.length > 0){
				for(var i = 0, len = _handlers.length; i < len; i++){
					eventResults.push(_handlers[i].apply(this, args));
				}
			}
			if(_oneTimeHandlers && _oneTimeHandlersLen> 0){
				for(var i = 0; i < _oneTimeHandlersLen; i++){
					eventResults.push(_oneTimeHandlers[i].apply(this, args));
					
				}
			}
			_oneTimeHandlers=[];
			return eventResults.length == 1 ? eventResults[0] : eventResults;
             
		};
		
	}
	var createScript = function(url,onload) {
		var _script = document.createElement('script');
		_script.type = 'text/javascript';
		_script.charset = 'utf-8';
		_script.async = true;
		_script.src = url;
		if(onload){
			_script.onload = function(){
				onload();
			};
		}
		var firstScript = document.getElementsByTagName('script')[0];
		if(firstScript){
			firstScript.parentNode.insertBefore(_script, firstScript);
		}else{
			 head.appendChild(_script);
		}
	};
	
	var loadMod = function(modName, callback) {
		 
		var mod = moduleCache[modName];
		if(mod){
			if(mod.status == 'loaded'){
				setTimeout(callback(mod.export), 0);
				
			}else{
				mod.one('loaded', callback);
			}
		}else{
			mod = moduleCache[modName] = new Mod({
				modName : modName,
				status : 'loading',
				export : null
			});
			mod.one('loaded', callback);
			createScript(modName + ".js");
		}
		
	};
	
	var saveModule = function(modName, params, factory){
		console.log('modName='+modName);
		var _export = (typeof factory == 'function') ? factory.apply(null, params) : factory;
		
		if(modName){
			var mod = moduleCache[modName];
			mod.status = 'loaded';
			mod.export = _export;
			mod.fire('loaded', mod.export);
		} 
		
	};
	
	var ISF = {
		
		loadModule : function(modName, factory, config) {
			config = config ||{};
			
			var requires = config.requires;

			if (requires && requires.length) {
				var params = [],
					depCount = 0;
				for (i = 0, len = requires.length; i < len; i++) {
					(function(i) {
						// 依赖加 1
						depCount++;

						loadMod(requires[i], function(param) {
							params[i] = param;
							depCount--;
							if (depCount == 0) {
								saveModule(modName, params, factory);
							}
						});
					})(i);
				}
			} else {
				saveModule(modName, [], factory);
			}
		},
		
		define : function(moduleName, factory, config) {
			this.loadModule(moduleName, factory, config);
		},
		
		use: function(modules, factory){
			this.loadModule(undefined, factory, {requires:modules});
		}

	};
	return ISF;

})(window, document);

测试:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title></title>
  <script src="ISF.js" type="text/javascript"></script>
</head>
<body>
</body>

<script type="text/javascript">
ISF.use(['util', 'math', 'num'], function (util, math, num) {
  num = math.getRadom() + '_' + num;
  num = util.formatNum(num);
  console.log(num);
});
</script>
</html>
ISF.define('math', function (num) {
  return {
    getRadom: function () {
      return parseInt(Math.random() * num);
    }
  };
}, {requires:['num']});
ISF.define('num', function () {
   return 10;
 });
ISF.define('util', function () {
  return {
    formatNum: function (n) {
      if (n < 10) return '0' + n;
      return n;
    }
  };
});

相关推荐