好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

判定模块加载时是否存在循环依赖

判定模块加载时是否存在循环依赖

循环依赖是所有语言的加载器都是大头的问题,除非你的模块都是像spring那么利用Ioc进行控制反转,那么出现循环依赖就是死结。对此,我们唯一能做的事是,在第一个循环依赖出现时就立即通知用户查看它们的依赖列表。

在AMD大肆普及动态加载的好处后,大家应该隐藏知道有两个方法干这事。一个定义模块的define方法,另一个是加载模块的require方法。

define方法的参数为define(name?, deps? ,factroy), 换言之模块名与依赖列表都不是必须的,require参数为require(names , callback)。当我们用require一组模块,将它们的返回值传到回调中前,它实质上做了许多事情,其中为了实现跨域加载脚本,我们使用了script标签进行加载。但这不重点。script标签加载回来的脚本有个严格的格式,里面就是一个define方法。这与JSONP非常相近。为了实现匿名模块,我们通常不使用第1个参数,但第2参数有时就不能省略。不过没有问题,我们可以从请求的URL中还原回模块名,因此最终还是得到三个参数,第二个参数依赖列表不存在,我们就置为空数组。当一个模块被加载回来,并且它的依赖列表为空,我们就可以说它是可用的。若一个模块存在依赖列表,那么当它的所有模块都可用时,它才可用。当两个模块存在循环依赖时,就变成你等我,我等你的状态,因此在每加载一个模块回来时,就检测它的依赖列表,不断回溯它的上级依赖,上上级依赖,但这些链中是否存在我们当前这个模块名。如果有就是循环依赖,立即抛错。这个检测我们也可以做些优化,这因为这是个图,经过的路径会非常复杂,我们可以跳过所有已发出请求但没有加载回来的模块或所有可用的模块。

//这些是定义在种子模块(核心模块)中

var   loadings = []; var   modules = {};

 

function   define(name, deps, factory){

     var   el = modules[name] = {

         deps:deps,

         name: name,

         factory:factory,

         status: !deps.length //是否可用

     }

 

     if (!el.status){ //踢进列队进行检测

         loadings.push(el);

     }

     _checkDeps();

     if ( _checkCircle(deps, name) ){

         throw   new   Error( name + "模块与之前的某些模块存在循环依赖" )

     }

}

function   _checkCircle(list, nick){ //检测是否存在循环依赖

     for ( var   i = 0, name; name = list[ i++ ];){

         var   el =  modules[name];

         if (el ){

             if ( el.name == nick || el.deps.length && _checkCircle(el.deps, nick)){

                 return   true ;

             }

         }

     }

}

function   _checkDeps(){ //检测模块有没有加载成功

     loop:

     for   ( var   i = loadings.length, el; el = loadings[ --i ]; ) {

         var   deps = el.deps;

         var   ok = true ;

         for ( var   j = 0, name; name = deps[j++];){

             if (!modules[name] || !modules[name].status){

                 ok = false ;

                 continue   loop

             }

         }

         if (ok){

             el.status = true ;

             loadings.splice( i, 1 );

             _checkDeps()

         }

     }

}

//这是a.js的内容

define( "a" ,[ "b" ])

//这是b.js的内容

define( "b" ,[ "c" ])

//这是c.js的内容

define( "c" ,[ "a" ])

//方便自己用firebug肉眼确认

console.log(modules)

console.log(loadings)

上面只是判定依赖关系的代码,实质上模块加载系统非常复杂,分为拆分模块名,别名映射,转换为URL,创建加载用的iframe与script(iframe是为了更好地在opera与旧式IE判定死链),处理加载回来define方法的最后一个参数factory,还原它模块名,判定是否可用,是否循环依赖,如果存在依赖再加载它的依赖等步骤,具体搜我博客有关模块加载的其他文章。

 

 

标签:  javascript ,  mass

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于判定模块加载时是否存在循环依赖的详细内容...

  阅读:52次