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. 运行PHP

    /usr/local/php/bin/php /home/www/index.php

  2. SQL分页存储过程(不支持多表联合查询,不支持多字段排序)

    CREATE PROCEDURE [dbo].[Pro_GetPageOfRecords] @PageSize INT=20, --分页大小 @CurrentPage INT, --第几页 @Clum ...

  3. CentOS 6.5系统安装配置图解教程(详细图文)

    转载:http://www.jb51.net/os/128751.html

  4. easui tree载入时自动展开无子节点的节点

    利用loadFilter对后台返回的原始数据进行过滤处理,将数据中的state字段修改相应的值,若无子节点,则改成open,若有子节点,则改成closed. 由于一个node属性只有下面几项内容,因此 ...

  5. stl源代码剖析:编译器的提前定义位置集设置

    眼下我的工作环境还是win.全部演示也用VS或者cygwin这些环境作为基础. 1.配置项目的附加include目,添加提前定义位置集设置,编译器会把它添加include路径,比方在某个目录中定义一个 ...

  6. iReport5.6.0 linechart 制作方法

    iReport 官网和文档上关于chart设计以饼图和JDBC源作为样例.但很多其它的情况下因为报表中的数据须要首先加工处理,因此很多其它的是从JavaBeans set datasource从获取数 ...

  7. TCP/IP之TCP连接的建立与中止状态分析

    TCP连接的建立可以简单的称为三次握手,而连接的中止则可以叫做四次握手. 1.连接的建立: c端发起请求同步(用SYN段等于1的TCP报文),确认某个端口是否监听: s端应答(用ACK段等于1的TCP ...

  8. sql 合并相同条件的字段

    案例:将 Albums 字段相同的数据的 PhotoUrl 字段 拼接到一起(我写的是前9行,可以去掉) 一.表的结构 二.sql 语句(为了方便 我加了一个条件[Albums=783] ) ) '; ...

  9. Xcode插件(一)-规范注释生成器VVDocumenter

    原文来自:http://blog.csdn.net/hitwhylz/article/details/27813315 分享几个常用的Xcode插件. 第一个, 规范注释生成器VVDocumenter ...

  10. HDU 4267 线段树 离散点区间更新, 自叶子节点至根单点查询

    题意: n个数字 下面n个数字表示数列 2个操作 1 [u, v]  k  add [u,v ]区间 (u点要计算)每隔k个位置,该数字+add 2 pos 询问 pos下标的值(下标从1开始) 思路 ...