前端之家收集整理的这篇文章主要介绍了
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]);
}
}
}
})();
};