论坛首页 Web前端技术论坛

JSI代码分析

浏览 2723 次
锁定老帖子 主题: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(',')+']');
                while(index--){
                    objectMap[names[index]] = values[index];
                }

在这里JSI利用loader.hook提取出脚本在声明的对象并传给Package.objectMap

第102行

 target[objectNames[i]]=packageObject.objectMap[objectNames[i]];

把对象从package.objectMap传给Import中声明的target对象,或者Import执行时的scope对象

 

 

  • 大小: 31.7 KB
  • 大小: 35.7 KB
   发表时间:2008-12-24  
图文并茂,分析到位。
我把这篇文章收录到JSI专栏了^_^
0 请登录后投票
   发表时间:2009-03-16   最后修改:2009-03-16
你有一次修改是不对的:

if(debugMode){ 


源代码应该是:
if(":debug"){ 


大多数人一定会为后者疑惑。
这是JSA特征编译的手法,这种针对字符串常量的条件块,JSA都会自动清理,除非你指定了某个特征需求。
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics