程序员 2014-11-5 每日奇妙之旅
程序员 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模式