kmdjs和循环依赖

循环依赖是非常必要的,有的程序写着写着就循环依赖了,可以提取出一个对象来共同依赖解决循环依赖,但是有时会破坏程序的逻辑自封闭和高内聚。所以没解决好循环依赖的模块化库、框架、编译器都不是一个好库、框架、编译器。

kmdjs的本质就是{},从{}扩展出的tree。从很早的版本就开始,是支持循环依赖的。比如下面的代码:

define('namespace1.A',['namespace2'], {
ctor: function () {
this.b = new B();
}
}) define('namespace2.B',['namespace1'] , {
ctor: function () { },
xx: function () {
var a = new A();
}
})

会被kmdjs编译成:

var namespace1 = {};
var namespace2 = {}; namespace1.A = Class.extend({
ctor: function () {
this.b = new namespace2.B();
}
}) namespace2.B = Class.extend({
ctor: function () { },
xx: function () {
var a = new namespace1.A();
}
})

要支持循环依赖其实有个要求,就是lazy using不是lazy using的循环依赖是无解的循环依赖
怎么理解上面这句话呢?看上面的代码,Class.extend执行完之后,各自依赖的东西是不会被调用的。
A代码里的new namespace2.B()要在new namespace1.A的时候才会被调用。
B代码里的new namespace1.A()要var a = new namespace1.A;a.xx()之后被调用后才会被执行。
所以在初始化阶段,这样的循环依赖是被允许的,因为都是lazy using。只要满足lazy using,执行顺序就不重要了,如果不是lazy using(如静态属性方法的设置),执行顺序就必须把依赖的项先执行。
如上面所说,不是所有的循环依赖都能够解决的,比如看C#里面的无解的循环依赖的例子:

namespace Project1
{
public class A
{
public static B b = new B();
}
} namespace Project1
{
public class B
{
public static A a = new A();
}
}

上面的代码编译时候就会报错。怎么改成有解,那么就要lazy using:

namespace Project1
{
public class A
{
public static B b = new B();
}
} namespace Project1
{
public class B
{
public int testMethod()
{
A a = new A();
return 1;
}
}
}

这样的依赖编译器是可以解决的。

kmdjs 0.1.4

kmd的意思是 kernel module definition。该版本和以前的主要变化如下:

  1. kmdjs文件大小从以前的一万多行代码变成了一百多行代码
  2. 从以前的namespace+class组织项目变成namespace+module组织项目

kmdjs API

kmdjs.config
用于配置 namespace + module和文件路径的mapping

kmdjs.config({
'util.bom':'js/util/bom.js',
'app.Ball':'js/ball.js',
'util.dom':'js/util/dom.js',
'util.dom.test':'js/util/test.js',
'main': 'js/main.js'
});

kmdjs.main
程序的入口代码。
kmdjs.define
定义模块

kmdjs.define('main',['util.bom','app.Ball','util.dom.test'], function(bom,Ball,test) {

    var ball = new Ball(0, 0, 28, 1, -2, 'kmdjs');
alert(test.m(3, 3));
var vp = bom.getViewport(); setInterval(function () {
ball.tick();
(ball.x + ball.r * 2 > vp[2] || ball.x < 0) && (ball.vx *= -1);
(ball.y + ball.r * 2 > vp[3] || ball.y < 0) && (ball.vy *= -1);
}, 15); });

如果只传两个参数,代表不依赖任何模块。这里和AMD一样,在factory的回调里把依赖注入到里面。
但是也直接在代码里把namespace写进去访问,如下所示:

kmdjs.define('main',['util.bom','app.Ball'], function() {

    var ball = new app.Ball(0, 0, 28, 1, -2, 'kmdjs');
var vp = util.bom.getViewport(); setInterval(function () {
ball.tick();
(ball.x + ball.r * 2 > vp[2] || ball.x < 0) && (ball.vx *= -1);
(ball.y + ball.r * 2 > vp[3] || ball.y < 0) && (ball.vy *= -1);
}, 15); });

而有的时候必须使用上面这种方式用来解决循环依赖导致执行顺序问题带来的注入undefined:如:

kmdjs.define("util.dom",['util.bom'] ,function(bom){
var Dom={}; Dom.add = function(a,b){
//循环依赖导致的bom undefined,所以这里写上namespace
return util.bom.sub(a,b);
} return Dom;
});

kmdjs.define("util.bom",["util.dom"], function(dom){
var Bom={}; Bom.getViewport=function() {
alert(dom.add(1,4)); }; Bom.sub = function(a,b){
return a-b;
};
return Bom;
});

bundler

可以通过main传入回调函数,在回调函数中拿到编辑打包好的字符串。

kmdjs.main(function(bundler){
alert(bundler)
});

如上面的例子打包出来的代码:

var util={};
var app={};
util.dom={};
var main={}; util.dom = (function (bom){
var Dom={}; Dom.add = function(a,b){
return util.bom.sub(a,b);
} return Dom;
})(util.bom); app.Ball = (function (){
var Ball = function (x, y, r, vx, vy, text) {
this.x = x;
this.y = y;
this.r = r;
this.d = 2 * r;
this.vx = vx;
this.vy = vy;
this.element = document.createElement("div");
this.element.innerHTML = text; this.element.style.cssText = "text-align:center;position:absolute; -moz-border-radius:" + this.d + "px; border-radius: " + this.d + "px; width: " + this.d + "px; height: " + this.d + "px;line-height:" + this.d + "px;color:white;";
document.body.appendChild(this.element); }; Ball.prototype.tick= function () {
this.x += this.vx;
this.y += this.vy;
this.element.style.left = this.x + "px";
this.element.style.top = this.y + "px";
}; return Ball;
})(); util.dom.test = (function (){
var Element={}; Element.m = function(a,b){
return a*b;
} return Element;
})(); util.bom = (function (dom){
var Bom={}; Bom.getViewport=function() {
alert(dom.add(1,4));
var d = document.documentElement, b = document.body, w = window, div = document.createElement("div");
div.innerHTML = " <div></div>";
var lt = !(div.firstChild.nodeType === 3) ?
{ left: b.scrollLeft || d.scrollLeft, top: b.scrollTop || d.scrollTop } :
{ left: w.pageXOffset, top: w.pageYOffset };
var wh = w.innerWidth ?
{ width: w.innerWidth, height: w.innerHeight } :
(d && d.clientWidth && d.clientWidth != 0 ?
{ width: d.clientWidth, height: d.clientHeight } :
{ width: b.clientWidth, height: b.clientHeight }); return [lt.left, lt.top, wh.width, wh.height]
}; Bom.sub = function(a,b){
return a-b;
};
return Bom;
})(util.dom); main = (function (bom,Ball,test) { var ball = new Ball(0, 0, 28, 1, -2, 'kmdjs');
alert(test.m(3, 3));
var vp = bom.getViewport(); setInterval(function () {
ball.tick();
(ball.x + ball.r * 2 > vp[2] || ball.x < 0) && (ball.vx *= -1);
(ball.y + ball.r * 2 > vp[3] || ball.y < 0) && (ball.vy *= -1);
}, 15); })(util.bom,app.Ball,util.dom.test);

Github

https://github.com/kmdjs/kmdjs

 
好文要顶 关注我 收藏该文

js和循环依赖的更多相关文章

  1. Node.js的循环依赖

    我们知道在实际编程过程中,要尽可能的减少或者规避循环依赖情况的发生.但在现实环境中,有时却不得不产生循环依赖.Node.js不提倡使用循环依赖,但真有如此情况发生时Node.js也有办法解决.这篇博文 ...

  2. Node.js之循环依赖

    在Node.js中有可能会出现循环依赖的问题,在此做一个简单的记录 假如有一个模块A: exports.loaded = false; const b = require('./b'); module ...

  3. kmdjs和循环依赖

    循环依赖 循环依赖是非常必要的,有的程序写着写着就循环依赖了,可以提取出一个对象来共同依赖解决循环依赖,但是有时会破坏程序的逻辑自封闭和高内聚.所以没解决好循环依赖的模块化库.框架.编译器都不是一个好 ...

  4. seaJS循环依赖的解决原理

    seajs模块的六个状态. var STATUS = {  'FETCHING': 1, // The module file is fetching now. 模块正在下载中  'FETCHED': ...

  5. RequireJS模块化之循环依赖

    如果你定义一个循环依赖关系 (a 依赖b 并且 b 依赖 a),那么当b的模块构造函数被调用的时候,传递给他的a会是undefined. 但是b可以在a模块在被引入之后通过require(‘a’)来获 ...

  6. 3.4 spring5源码系列--循环依赖的设计思想

    前面已经写了关于三篇循环依赖的文章, 这是一个总结篇 第一篇: 3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖 第二篇: 3.2spring源码系列----循环依赖源 ...

  7. spring3 循环依赖

    循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环.此处不 ...

  8. 在.NET Core中遭遇循环依赖问题"A circular dependency was detected"

    今天在将一个项目迁移至ASP.NET Core的过程中遭遇一个循环依赖问题,错误信息如下: A circular dependency was detected for the service of ...

  9. Atitit js中的依赖注入di ioc的实现

    Atitit js中的依赖注入di ioc的实现 全类名(FQCN)为标识符1 混合请求模式1 使用类内  builder  即可..2 Service locator method走ok拦2 Jav ...

随机推荐

  1. (IOS)数据持久化

    1.属性列表序列化 2.模型对象归档 3.嵌入式SQLite3 4.Core Data 5.应用程序设置 6.UIDocument管理文档存储 7.iCloud Demo界面: 1.属性列表序列化 即 ...

  2. CentOS 6.5(64bit)安装GCC4.8.2+Qt5.2.1(替换GCC的链接库)

    截至目前,Qt的最新版本为5.2.1,CentOS的版本为6.5,GCC的版本为4.8.2,经过一番尝试,终于将Qt开发环境安装到了CentOS(64 bit)中,整个过程中有几个需要注意的地方,在这 ...

  3. android串行化getSerializable、getSerializableExtra

    android串行化getSerializable.getSerializableExtra 传参 总结 案例1 不用 Bundle 封装数据 提交activity lst.setOnItemClic ...

  4. 高屋建瓴 cocos2d-x-3.0架构设计 Cocos2d (v.3.0) rendering pipeline roadmap(原文)

    Cocos2d (v.3.0) rendering pipeline roadmap Why (the vision) The way currently Cocos2d does rendering ...

  5. OTN交换&amp;P-OTN有效减少100G网络成本(一)

    近年来.网络运营商一直严重依赖基于ROADM的光传送设备,利用固定的点到点WDN联接.利用10G波长在整个城域网和广域网中汇聚及传送client业务.假设这些网络经过精细的设计规划,也能够合理.有效地 ...

  6. ThinkPHP - 每个操作都检测用户是否登录

    TP提供了一个自动执行的函数_initialize(), 你创建一个公共控制器CommonAction.class.php文件. 定义了此方法,不能存在构造方法__construct() <?p ...

  7. 杭电 2029 Palindromes _easy version

    Problem Description "回文串"是一个正读和反读都一样的字符串,比如"level"或者"noon"等等就是回文串.请写一个 ...

  8. java 如何自定义异常 用代码展示 真心靠谱

    先建两个自定义的异常类 ChushufuException类 class ChushufuException extends Exception { public ChushufuException( ...

  9. Google Code Jam Round 1A 2015 Problem B. Haircut 二分

    Problem You are waiting in a long line to get a haircut at a trendy barber shop. The shop has B barb ...

  10. Altera FPGA中的pin进一步说明

    最近END china上的大神阿昏豆发表了博文 <FPGA研发之道(25)-管脚>,刚好今天拿到了新书<深入理解Altera FPGA应用设计>第一章开篇就讲pin.这里就两者 ...