当前位置: 代码迷 >> Web前端 >> 模块的静态与动态循环依托
  详细解决方案

模块的静态与动态循环依托

热度:89   发布时间:2012-10-18 13:46:56.0
模块的静态与动态循环依赖

场景:

?

循环依赖 我是不支持的,但现实中似乎又确实需要循环依赖,例如前端的选择器场景 (ie<8):

?

首先实现了 DOM 模块来保证各个浏览器的兼容性以及 api 的易用性,其中包含必要简单的选择器逻辑

?

然后实现了高级选择器模块,但这并不是最常用,为了效率该模块是不放入核心 DOM 模块中的,而选择将它作为独立模块 :selector,显然 selector 模块依赖于 DOM 进行 dom 遍历.

?

S.add("selector",function(){

},{requires:["dom"]});

?

而 DOM 中会进行判断是否当前选择器字符串过于负责而自己不能处理,需要高级选择器模块介入:

?

S.add("dom",function(S,Selector){
  return {
      querySelectorAll:function(q){
           if(isAdvanced(q)){
               return Selector.querySelectorAll(q);
           } else{
               // simple logic
           }
      }
  };
},{requires:["selector"]});

?

这时就形成了循环依赖

?

解决:

?

其实我们需要区分模块间到底是静态依赖还是动态依赖,静态依赖指模块的初始化就需要另一个模块参与,而动态依赖则是指直到模块的运行期才会需要调用另一个模块,对于静态循环依赖这个问题我觉得是无解的,而对于动态循环依赖则是完全可以绕过.

?

动态循环依赖可以参考类似 serviceloader 的做法,DOM 模块完全可以动态取得高级选择器接口的一个具体实现模块,而selector 模块实现接口并保证自己可以被找到即可:

?

DOM 模块:

?

S.add("dom",function(S){
  return {
      querySelectorAll:function(q){
           if(isAdvanced(q)){
               return S.ServiceLoader.load("selector").querySelectorAll(q);
           } else{
               // simple logic
           }
      }
  };
});

?

高级选择器模块仍可以依赖 DOM ,实现 querySelectorAll 接口(概念上,动态语言完全没必要),并注册自己即可.

?

而 ServiceLoad.load 完全可以和模块系统结合在一起,用户可以通过模块系统静态或动态载入一些高级附加模块,ServiceLoad.load 询问模块系统即可得到实现了高级选择器接口的具体模块.

?

?

?

refer:

?

static vs dynamic 1 ,2

?

circular dependency wiki

?

java.util.ServiceLoader api

?

?

?

1 楼 limu 2011-07-25  
我也遇到这个问题,在seajs里遇到类似的问题.
把动态依赖的require改为require.async.
因为初始时一定是require过这俩,require.async的目标模块在调用时肯定已经被载入
所以调用时就是同步的,可以按同步的写法继续写余下的代码,而不用封装到回调中.
2 楼 yiminghe 2011-07-25  
limu 写道
我也遇到这个问题,在seajs里遇到类似的问题.
把动态依赖的require改为require.async.
因为初始时一定是require过这俩,require.async的目标模块在调用时肯定已经被载入
所以调用时就是同步的,可以按同步的写法继续写余下的代码,而不用封装到回调中.

哈,kissy 一直是通过 S.require("sizzle") 来解决的,不过看到后端语言的对应支持很踏实
  相关解决方案