程序员 2014-11-5 每日奇妙之旅
发布于 3个月前 作者 leogiese 496 次浏览 来自 分享

原文 http://forjs.org/book/xyfULqrrXg/section/x1lbNO2Rmwl

程序员 2014-11-5 每日奇妙之旅

推荐:《精通Node.js开发》 《Angular.js视频详解》 腾讯QQ 1405491181 微信号 forjs_org

早上起来,缺少能量有些晕,做了点白米饭,希望做好了后可以补充能量。一杯带盐的温水是个好的开始,让我感脚好多了,而咖啡要早餐后才喝。

昨天进展很不错,今天希望完成domain框架的preview,难点在于eventbus的实现。还有是Actor 模拟 saga的方式,需要打磨一下。

当一个actor调用另一个actor时,如何处理这个通信机制?这点需要思考思考…

应该给被调用者 方法 参数暴露一个 caller

changeName(data,di){
    var call = di.call;
    var caller = di.caller; // {id,typeName}
    var apply = di.apply;
    var listen = di.listen;
}

两个Actor 通信,需要一个 context 上下文标记

那么这个context标记,应该体现在 apply 方法调用上

apply(name,data,true) // true 表示开始context

当然也应该体现在 call 方法上

call(commandName, data, caller,context) {

首先对apply做了修改,加入context支持

[apply](name, data, caller = {},contextId = null) {
    if (this.get("alive")) {
        var event = new Event(name, {
            callerId: caller.id,
            callerType: caller.typeName,
            targetId: this.get("id"),
            targetType: this.typeName,
            contextId: contextId,
            data: data
        });
        this[when](event, this[set].bind(this));
        this.uncommittedEvents.push(event);
        this.emit("apply", this);
    }
}

然后是 call 方法,也相应的加入context的支持

call(commandName, data={}, caller={},contextId=null) {
    this[commandName](data, {
        apply: (eventName, data , cxt)=> {
            this[apply](eventName, data, caller,cxt || contextId);
        },
        listen: this[listen].bind(this)
    });
}

并对listen作修改,onlyContext 表示是否只监听context内的事件。

[listen](eventName, handleName, onlyContext) {
    this.emit('listen', this, eventName, handleName,!!onlyContext);
}

对 call方法进一步修改,增加了service.call ,目的是内部方法调用其他actor时候用。

call(commandName, data = {}, caller = {}, contextId = null) {
    this[commandName](data, {
        apply: (eventName, data, cxt)=> {
            this[apply](eventName, data, caller, cxt || contextId);
        },
        // 新修改的
        listen: (eventName, handleName, cxt, onlyContext)=> {
            if(cxt === true){
                onlyContext = cxt;
                cxt = contentId
            }

            this.emit('listen', this, eventName, handleName, cxt || contextId,onlyContext);
        },
        // 新增加的
        call: (actorId,commandName,data,cxt)=> {
            this.emit("call",actorId,commandName,data,this, cxt || contextId);
        }
    });
}

总结以下actor会emit那些事件

call 事件表示它要调用其他actor方法
  • actorId
  • commandName
  • data
  • [cxt] 可选,如果不选择,会继承上一步的contextId
listen 事件表示它要监听一个领域事件
  • eventName 监听的事件,例如 User.id001:changeName
  • handleName 事件处理器的名称
  • cxt 如果为 null 将继承上一步 contextId
  • onlyContext 表示仅监听cxt的对应事件
apply 事件表示,它要发出领域事件。
  • eventName 事件名
  • data 事件信息
  • caller 事件产生者
  • cxt 上下文ID
做个转账的Actor

var Transfer = Actor.extend({
    typeName:"Transfer",

    // 定义方法
    methods:{
        transfer(data,di){

            var from = data.from;
            var to = data.to;

            // 转账金额
            var money = data.money;

            // 监听from 的冻结事件
            di.listen("User."+from.id+":freeze", "freeze",true);

            // 监听to 的充值事件
            di.listen("User."+to.id+":recharge","recharge", true);


            // 监听from 完成付款事件
            di.listen("User."+from.id+":finishTransfer" , "fromFinishTransfer" , true);

            // 监听 to 完成充值事件
            di.listen("User."+from.id+":finishRecharge", "toFinishTransfer", true);

            // 调用from的 transfer 方法, 这一步会让from产生冻结事件
            di.call(from.id,"transfer",{money:money , transferId: this.id});


            di.apply("begin",data);

        }

        freeze(data,di){
            // 发出领域事件
            di.apply("freeze");

            // 调用 to 用户的充值方法
            var toUserId = this.get("to");
            var money = this.get("moeny");
            di.call(toUserId,"racharge",{money:money,reachargeId: this.id});
        }

        reacharg(){
            di.apply("recharge");

            // 调用 from用户的 finishTransfer 方法
            var fromUserId = this.get("from");
            var money = this.get("moeny");
            di.call(fromUserId,"finishTransfer",{transferId:this.id});
        }

        fromFinishTransfer(data,id){
            di.apply("finishTransfer");

            // 调用 from用户的 finishTransfer 方法
            var fromUserId = this.get("from");
            var money = this.get("moeny");
            di.call(fromUserId,"finishTransfer",{transferId:this.id});
        }

    }
})
2 回复

沙发。。。虽然不太懂,但好腻害的赶脚。。。

就是 cqrs 和 actor模式

回到顶部