锁定老帖子 主题:JSI代码分析
精华帖 (21) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-12-13
最后修改:2009-11-05
一、$import流程图
二、doScriptImport流程图
三、JSI导入js关键代码分析
function loadDependence(data,vars){ loadScript(data[0],data[1],data[2]); var objectMap = data[0].objectMap; var names = data[5]; var i = names.length; while(i--){ var name = names[i]; vars.push(name);//对于转载后依赖,我们使用重复设置了一次 vars[name] = objectMap[name]; } } function prepareScriptLoad(packageObject,loader){ var name = loader.name; var deps = packageObject.dependenceMap[name]; var varText = 'this.hook=function(n){return eval(n)}'; var vars = []; var i = deps && deps.length; while(i--){ var dep = deps[i]; var key = dep[3] || 0; //? 0 if(dep[4]){//记录依赖,以待装载 dep[4]=> true 载入后依赖 vars.push.apply(vars,dep[5]); //把dep[5]=> if(map){ if(map[key]){ map[key].push(dep); }else{ map[key] = [dep] } }else{ //函数内只有一次赋值(申明后置,也就你JavaScript够狠!! ) var map = loader.dependenceMap = {}; loader.initialize = scriptLoaderInitialize; map[key] = [dep] } }else{//直接装载(只是装载到缓存对象,没有进入装载单元),无需记录 //这里貌似有死循环的危险 loadDependence(dep,vars); if(dep = packageObject.loaderMap[name]){ return dep; } } } if(vars.length){ loader.varMap = vars; /** * this.hook = function(n){ * return eval(n) * }; * var obj1 = this.varMap.obj1, obj2 = this.varMap.obj2, obj3 = this.varMap.obj3 */ varText += ';var '+vars.join(',').replace(/([^,]+)/g,'$1 = this.varMap.$1'); } loader.varText = varText; } function doScriptLoad(packageObject,loader){ var name = loader.name; var packageName = packageObject.name; var cachedScript = getCachedScript(packageName,name); packageObject.loaderMap[name] = loader; try{ if(cachedScript instanceof Function){ //$JSI.preload(pkgName,name,'') cachedScripts[packageName][name]='';//clear cache return cachedScript.call(loader); }else{ //不要清除文本缓存 return freeEval.call(loader,'eval(this.varText);'+(cachedScript || loadTextByURL(packageObject.scriptBase+name))); } }catch(e){ if(debugMode){ if("org.xidea.jsi.boot:$log"){ $log.error("Load Error:\n"+loader.scriptBase + name+"\n\nException:"+e); } } throw e; }finally{ delete loader.varMap ; delete loader.varText ; var names = packageObject.scriptObjectMap[name]; var index = names.length; var objectMap = packageObject.objectMap; //此处优化不知有无作用 if(index == 1){ objectMap[names = names[0]] = loader.hook(names); }else{ var values = loader.hook('['+names.join(',')+']'); while(index--){ objectMap[names[index]] = values[index]; } } } } function doScriptImport(packageObject,fileName,target){ loadScript(packageObject,fileName); var objectNames = packageObject.scriptObjectMap[fileName]; //null不可hack if(target != null){ for(var i = 0; i<objectNames.length;i++){ target[objectNames[i]]=packageObject.objectMap[objectNames[i]]; } } } var $import = function(freeEval,cachedScripts){ ... }(function(){eval(arguments[0]);},{});
第38行 loadDependence(dep,vars); 在这里JSI把待载入脚本[依赖]的对象存入vars,在第45赋值给了loader.varMap 第52行 对象名数组 => 对象声明语句 varText += ';var '+vars.join(',').replace(/([^,]+)/g,'$1 = this.varMap.$1'); 第 16行 var varText = 'this.hook=function(n){return eval(n)}' ; 这是JSI把载入脚本在loader下执行后能够获取引用到的关键技术 第69行 后台js文件---->前台---->call(loader,hook+js文件内容) return freeEval.call(loader,'eval(this.varText);'+(cachedScript || loadTextByURL(packageObject.scriptBase+name))); 在这里JSI把js文件从后台通过xmlhttp从后台载入,然后在loader这个scope中执行(避免命名污染),此时loader.hook被放到了与执行js的同一个上下文中 第88-91行 loader => package var values = loader.hook('['+names.join(',')+']'); 在这里JSI利用loader.hook提取出脚本在声明的对象并传给Package.objectMap 第102行 target[objectNames[i]]=packageObject.objectMap[objectNames[i]]; 把对象从package.objectMap传给Import中声明的target对象,或者Import执行时的scope对象
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-12-24
图文并茂,分析到位。
我把这篇文章收录到JSI专栏了^_^ |
|
返回顶楼 | |
发表时间:2009-03-16
最后修改:2009-03-16
你有一次修改是不对的:
if(debugMode){ 源代码应该是: if(":debug"){ 大多数人一定会为后者疑惑。 这是JSA特征编译的手法,这种针对字符串常量的条件块,JSA都会自动清理,除非你指定了某个特征需求。 |
|
返回顶楼 | |
浏览 2758 次