码迷,mamicode.com
首页 > 编程语言 > 详细

开坑!JavaScript AMD模块的设计与实现

时间:2014-08-18 00:19:23      阅读:386      评论:0      收藏:0      [点我收藏+]

标签:des   java   io   文件   for   ar   cti   amp   

开个坑,慢慢学习总结JavaScript的AMD规范

先把自己写的一个简易实现放上来,然后慢慢从0开始讲解一下AMD,已经如何自己动手实现一个AMD

/*AMD*/
var DOC = window.document;
var head = DOC.head || DOC.getElementsByTagName('head')[0];
var basePath = getCurrentScript(DOC);
basePath = basePath.substring(0, basePath.lastIndexOf('/')+1);

noop = function(){};
modules = {};

function getEmptyModule() {
	return {
		deps: [], 
		offers: [],
		state: 0,
		factory: noop
	};
};

function getCurrentScript(DOC){
	if (DOC.currentScript) {
		return DOC.currentScript.src; //FF,Chrome
	};
	var stack;
	try {
		a.b.c();
	} catch (e) {
		stack = e.stack; // 利用错误异常立刻抛出快速获得当前加载文件路径
		if (!stack && window.opera) {
			stack = String(e);
			if (!stack && window.opera) {
				stack = (String(e).match(/of linked script \S+/g) || []).join(" ");
			}
		};
	};
	if (stack) {
		stack = stack.split(/[@ ]/g).pop(); //取得最后一行,最后一个空格或@之后的部分
		stack = stack[0] === "(" ? stack.slice(1, -1) : stack;
		return stack.replace(/(:\d+)?:\d+$/i, ""); //去掉行号与或许存在的出错字符起始位置
	}
	// IE
	var nodes = head.getElementsByTagName("script");
	for (var i = 0, node; node = nodes[i++];) {
		if (node.readyState === 'interactive') {
			return node.src;
		};
	};
}

function getModuleName(url) {
	return url.substring(url.lastIndexOf('/')+1, url.lastIndexOf('.js'));
}

function require(list, factory) {
	var loaded = 0;
	var requires = list.length;
	var args = [];
	var id = getCurrentScript(DOC);
	var module = modules[id] ? modules[id] : getEmptyModule();
	module['factory'] = factory;
	modules[id] = module;

	for (var i=0; i<list.length; i++) {
		var depId = basePath+list[i]+'.js';	
		modules[depId] = modules[depId] ? modules[depId] : getEmptyModule();
		module['deps'].push(depId);
		if (modules[depId] && modules[depId].state === 2) {
			modules[depId].offers.push(id);
			loaded++;
			args.push(modules[depId].exports);
		//此依赖模块正在被加载中
		} else if(modules[depId] && modules[depId].state === 1) {
			modules[depId].offers.push(id);
		//此依赖模块从未加载过
		} else {
			//loadJS加载模块js,模块js调用define,define又会require加载此模块需要的依赖
			//从而函数进入递归追踪并加载此模块所有直接和间接依赖
			modules[depId].offers.push(id);
			loadJS(depId);
		};
	};
	if (loaded === requires) {
		module.factory.apply(null, args)
	};
};

function loadJS(url) {
	var module = modules[url];
	var node = DOC.createElement('script');	
	node.onload = node.onreadystatechange = function() {
		if (/loaded|complete/i.test(node.readyState) || !node.readyState) {

		};
	};
	node.src = url;
   head.insertBefore(node, head.firstChild);
};

function findFishedModules(url) {
	var ret = [];
	var deped = modules[url];
	var moduleIds = deped.offers;
	for (var i = 0; i < moduleIds.length; i++) {
		var id = moduleIds[i];
		var deps = modules[id].deps;
		var flag = false;
		for (var j = 0; j < deps.length; j++) {
			var dep = modules[deps[j]];
			if (dep.state == 2 || deps[j] == url) {
				flag = true;
			};
			if (dep.state != 2) {
				flag = false;
				break;
			};
		};
		if (flag) {
			console.info('模块'+getModuleName(id)+'已可用');
			ret.push(id);
		};
	};
	return ret;
};

function fireFactory(root) {
	var finshedIds = findFishedModules(root);
	for (var i = 0; i < finshedIds.length; i++) {
		var module = modules[finshedIds[i]];
		module.factory.apply(null, getDepsModules(module.deps));
		fireFactory(finshedIds[i]);
	};
};

function getDepsModules(deps) {
	var args = [];
	for (var i = 0; i < deps.length; i++) {
		var dep = deps[i];
		args.push(modules[dep].exports);
	};
	return args;
};

function define(deps, factory) {
	var id = getCurrentScript(DOC);
	//如果此模块没有依赖立即安装该模块
	if (deps.length == 0) {
		modules[id].exports = factory.apply(null);
		modules[id].state = 2;
		//从依赖的叶子一直往上找一系列的触发安装
		fireFactory(id);
		return;
	};
	require(deps, function(){
		var _deps = [];
		for (var i = 0; i < deps.length; i++) {
			_deps.push(basePath+deps[i]+'.js');
		};
		modules[id].exports = factory.apply(null, getDepsModules(_deps));
		modules[id].state = 2;
	});
};


开坑!JavaScript AMD模块的设计与实现,布布扣,bubuko.com

开坑!JavaScript AMD模块的设计与实现

标签:des   java   io   文件   for   ar   cti   amp   

原文地址:http://blog.csdn.net/songzheng_741/article/details/38646785

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!