资讯专栏INFORMATION COLUMN

kmdjs和循环依赖

AlienZHOU / 1055人阅读

摘要:从很早的版本就开始,是支持循环依赖的。比如下面的代码会被编译成要支持循环依赖其实有个要求,就是。不是的循环依赖是无解的循环依赖。所以在初始化阶段,这样的循环依赖是被允许的,因为都是。

循环依赖

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

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。该版本和以前的主要变化如下:

kmdjs文件大小从以前的一万多行代码变成了一百多行代码

从以前的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;background-color:green;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 = "  
"; 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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79656.html

相关文章

  • kmdjs集成uglifyjs2打造极致的编程体验

    摘要:怎样才算更好不用依赖注入不用写,自动匹配依赖如下所示这就要借助能力,把的字符串替换成带有就可以实现上面的效果。再也不用区分循环依赖和非循环依赖了上面的所有代码可以上找到 回顾 上篇文章大概展示了kmdjs0.1.x时期的编程范式:如下面所示,可以直接依赖注入到function里, kmdjs.define(main,[util.bom,app.Ball,util.dom.test], ...

    Pink 评论0 收藏0
  • 用 Vue 来观察属性变化

    摘要:创建实例时,将遍历的属性,通过的将它们转为,在其内部可以追踪依赖通知变化。在内部,同是响应的观察属性变化的实例提供了方法,用于观察属性变化。 响应系统是 Vue 一个显著功能,修改属性,可以更新视图,这让状态管理变得非常简单且直观。创建 Vue 实例时,Vue 将遍历 data 的属性,通过 ES5 的 Object.defineProperty 将它们转为 getter/setter...

    hot_pot_Leo 评论0 收藏0
  • Qone 正式开源,使 javascript 支持 .NET LINQ

    摘要:下一代查询语言,使支持缘由最近刚好修改了腾讯文档表格公式的一些,主要是修改公式的。总的来说,因为腾讯文档公式相关工作早年的开发和开发,所以有了。让前端工程师通过字符串的形式实现了的调用下面统一叫做,即组成的。多数据源多数据源会产生笛卡儿积。 Qone 下一代 Web 查询语言,使 javascript 支持 LINQ Github: https://github.com/dntzha...

    JinB 评论0 收藏0
  • Qone 正式开源,使 javascript 支持 .NET LINQ

    摘要:下一代查询语言,使支持缘由最近刚好修改了腾讯文档表格公式的一些,主要是修改公式的。总的来说,因为腾讯文档公式相关工作早年的开发和开发,所以有了。让前端工程师通过字符串的形式实现了的调用下面统一叫做,即组成的。多数据源多数据源会产生笛卡儿积。 Qone 下一代 Web 查询语言,使 javascript 支持 LINQ Github: https://github.com/dntzha...

    sydMobile 评论0 收藏0
  • Spring源码分析:Spring的循环依赖分析

    摘要:我们知道为我们完全实例化好一个一定会经过一下三步实例化,其实也就是调用对象的构造方法实例化对象。循环依赖的产生定会发生在步骤和中,因为是利用构造方法,是利用属性赋值。 引言 基于Spring5+ 什么是循环依赖? 循环依赖有几种? Spring可以解决哪几种,为什么不能解决这几种? Spring是如何判断存在循环依赖的? 什么是循环依赖? 什么是循环依赖?我们都知道Spring最大...

    Cheng_Gang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<