Dojo源码分析(一)

前端之家收集整理的这篇文章主要介绍了Dojo源码分析(一)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
// dojo.js 负责加载代码和探测宿主系统环境
// dojo.js只加载一次,防止重复加载。
if(typeof dojo == "undefined"){
	
	// 匿名函数,这样写不会污染全局命名空间。所有函数内定义的变量都是局部变量。
	(function(){
	
		// 查找加载dojo.js的script标签,该标签就是rootNode。
		// 此函数返回一个匿名对象,其属性node代表rootNode,root是指dojo.js的根目录
		var getRootNode = function(){
			
			// 判断一下DOM树是否加载好
			if(this["document"] && this["document"]["getElementsByTagName"]){
			
				// 取出所有script标签
				var scripts = document.getElementsByTagName("script");
				
				// 正则表达式,用来匹配script的src属性,如果src是以dojo.js结尾或者是dojo.js加空白,就匹配成功,注意区分大小写。
				var rePkg = /dojo/.js(/W|$)/i;
				
				// 循环script标签
				for(var i = 0; i < scripts.length; i++){
				
					// script标签的src属性
					var src = scripts[i].getAttribute("src");
					
					// 如果script标签没有src属性,则跳过。例如,script代码段。
					if(!src){ continue; }
					
					// 匹配src属性,如果没有匹配上,则m=null
					var m = src.match(rePkg);
					if(m){
						// 匹配成功,直接返回
						return { 
							// rootNode,也就是加载dojo.js的script标签
							node: scripts[i],// dojo.js的根路径
							root: src.substring(0,m.index)
						};
					}
				}
			}
		}
		// 宿主环境
		var hostEnv = "browser";
		
		// 下面这段代码是判断宿主环境的,我们用浏览器访问,所以是默认值
		if(typeof djConfig !== "undefined" && djConfig.hostEnv){
			hostEnv = djConfig.hostEnv;
		}else if(
			typeof this["load"] == "function" &&
			(
				typeof this["Packages"] == "function" ||
				typeof this["Packages"] == "object"
			)
		){
			hostEnv = "rhino";
		}else if(typeof this["load"] == "function"){
			hostEnv = "spidermonkey";
		}
		
		// ["bootstrap.js","loader.js","hostenv_browser.js"]
		var tmps = ["bootstrap.js","hostenv_"+hostEnv+".js"];
		
		// Jaxer,ajax服务器,客户端和服务端都是用javascript开发,可以相互调用。我们这里可以略过。
		if (this.Jaxer && this.Jaxer.isOnServer) {
			this.load = Jaxer.load;
		}
	
		// djConfig,dojo的配置变量,在执行dojo.js就应该配置它,这里我们不配置它,就是undefined
		if(
			this["djConfig"]&&
			(
				djConfig["forceXDomain"] ||
				djConfig["useXDomain"]
			)
		){
			tmps.push("loader_xd.js");
		}
	
		if(this["djConfig"] && djConfig["baseUrl"]){
			// 如果我们定义了djConfig变量,设置了baseUrl属性,那就直接设置root值。也就是说我们不需要dojo自动探测baseUrl。
			var root = djConfig["baseUrl"];
		}else{
			// 定义root,给个初始值
			var root = "./";
			
			// 这个我们走不进去,因为我们是browser
			if(hostEnv === "spidermonkey"){
				// auto-detect the base path via an exception. Hack!
				try{
					throw new Error(""); 
				}catch(e){ 
					root = String(e.fileName || e.sourceURL).split("dojo.js")[0];
				}
			}
			
			// 如果没有定义djConfig,那么定义一个djConfig,而且初始化baseUrl属性
			if(!this["djConfig"]){
				djConfig = { baseUrl: root };
			}
	
			// DOM加载完成,这里我们就会走进来
			if(this["document"] && this["document"]["getElementsByTagName"]){
			
				// 调用getRootNode函数来给baseUrl赋值
				var root = getRootNode().root;	
				
				// 这句话有点多余,前面都定义过djConfig,还要再来一遍
				if(!this["djConfig"]){ djConfig = {}; }
				djConfig["baseUrl"] = root;
			}
		}
		
		// 取得root值后,就重新给tmps赋值
		for(var x=0; x < tmps.length; x++){
			tmps[x] = root+"_base/_loader/"+tmps[x];
		}
		
		// 加载base.js
		tmps.push(root+"_base.js");
		// lastRoot就是rootNode
		var lastRoot;
		var isOpera = 0;
		var isWebKit = 0;
		if(hostEnv == "browser"){
			try{
				lastRoot = getRootNode().node;
				var ua = navigator.userAgent;
				isOpera = (ua.indexOf("Opera") >= 0);
				isWebKit = (ua.indexOf("WebKit") >= 0);
			}catch(e){ /* squelch */ }
		}
		// 这里是动态加载script代码,所以要追加script标签。追加script标签大概有这么3种办法。
		// 第一种,是用DOM操作,往header标签里追加子标签。
		// 第二种,是用document.write方法直接写HTML代码
		// 第三种,是我看下面dojo代码才知道的,用XMLHttpRequest同步加载。
		// 动态加载的时候有一个时序问题,因为各个模块可能是有依赖关系。如果顺序错了,加载也会失败。
		// Opera 和 Safari在加载的时候不支持第一种,所以用第三种加载
		
		// XMLHttpRequest动态加载javascript代码,这里实现了第三种方法
		var injectXHRCode = function(src){
			var xhr = new XMLHttpRequest();
			// 第三个参数就是同步加载的意思
			xhr.open("GET",src,false);
			xhr.send();
			eval(xhr.responseText);
		}
	
		// 加载script代码,这里实现了第一种方法
		var injectScriptNode = function(src){
			if(isWebKit){ return injectXHRCode(src); }
			var head = document.getElementsByTagName("head")[0];
			var script = document.createElement("script");
			script.setAttribute("type","text/javascript");
			if(head.lastChild === lastRoot){
				head.appendChild(script);
			}else{
				lastRoot.parentNode.insertBefore(script,lastRoot.nextSibling);
			}
			script.src = src;
			lastRoot = script;
		}
		
		// 终于要开始加载了
		for(var x=0; x < tmps.length; x++){
			if(hostEnv === "rhino" || hostEnv === "spidermonkey" || (this.Jaxer && this.Jaxer.isOnServer)){
				// 这个分支走不进来,前面已经说过了
				load(tmps[x]);
			}else if(hostEnv === "ff_ext"){
				// 当是Firefox时候,这个需要你配置djConfig变量,才能走进来。默认即使是Firefox浏览器也走不进来
				var l = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
					.getService(Components.interfaces.mozIJSSubScriptLoader);
				l.loadSubScript(tmps[x],this)
			}else if(isOpera){ 
				// 当是Opera的时候用第三种方法加载
				injectXHRCode(tmps[x]);
			}else{
				// 其他场合,先用第二种方法加载,失败了再用别的
				try{
					document.write("<scr"+"ipt type='text/javascript' src='"+tmps[x]+"'></scr"+"ipt>");
				}catch(e){
					// strict XHTML mode,no document.write
					injectScriptNode(tmps[x]);
				}
			}
		}
	})();
};

猜你在找的Dojo相关文章