前言
在 上一篇实现了一个可以灵活拆卸的职责链,但是其中职责链节点都是同步请求的,同步返回一个标识是否继续请求下一个职责链节点。本文将介绍职责链节点中式异步请求的,该如何处理。
异步的职责链节点
当一个职责链节点的请求是异步时,在其中同步返回一个继续请求下一个节点的标识已经不起作用了,得给它一个方法自己向下一个节点发起请求。
于是给创建职责链节点的类加一个方法next,
class Chain{
constructor(fn){
this.fn = fn;
this.nextNode = null;
}
setNextNode(fn){
return this.nextNode = fn;
}
passRequest(){
const res = this.fn.apply(this,arguments);
if(res === 'toNextNode'){
return this.nextNode && this.nextNode.passRequest.apply(this.nextNode, arguments);
}
return res;
}
next(){
return this.nextNode && this.nextNode.passRequest.apply(this.nextNode, arguments);
}
}
然后这样使用:
const fn1 = new Chain(function () {
console.log(1);
return 'toNextNode';
});
const fn2 = new Chain(function () {
console.log(2);
var self = this;
setTimeout(function () {
self.next();
}, 1000);
});
const fn3 = new Chain(function () {
console.log(3);
});
fn1.setNextNode(fn2).setNextNode(fn3);
fn1.passRequest();
这里要注意fn1.setNextNode(fn2)返回的是fn2,故可以在fn1.setNextNode(fn2)后面直接调用setNextNode继续设计下一个职责链节点。
利用JavaScript的函数特性实现职责链模式
重写Function.prototype.after实现职责链模式。
Function.prototype.after=function(fn){
const self = this;
return function(){
const res = self.apply(this,arguments);
if(res == 'toNextNode'){
return fn.apply(this,arguments);
}
return res
}
}
const order = order1000.after(order500).after(orderNormal);
order(1,true,500);// 1000元定金预定,得到500元优惠券
这种把函数叠在一起的方式来实现职责链模式,虽然更加方便的创建职责链,但是也叠加了函数的作用域,如果链条太长的话,会对性能有较大的影响。
职责链模式的优点
在之前文章中已经说过,职责链模式的最大优点就是解耦了请求发送者和 N 个接收者之间的复杂关 系,由于不知道链中的哪个节点可以处理你发出的请求,所以你只需把请求传递给第一个节点即 可。
其次,使用了职责链模式之后,链中的节点对象可以灵活地拆分重组。增加或者删除一个节 点,或者改变节点在链中的位置都是轻而易举的事情。
职责链模式还有一个优点,那就是可以手动指定起始节点,请求并不是非得从链中的第一个
节点开始传递。比如在公交车的例子中,如果我明确在我前面的第一个人不是售票员,那我当然
可以越过他把一块钱递给他前面的人,这样可以减少请求在链中的传递次数,更快地找到合适的
请求接受者。这在普通的条件分支语句下是做不到的,在其中没有办法让请求越过某一个if判断。
另外,职责链模式使得程序中多了一些节点对象,可能在某一次的请求传递过程中,大部分 节点并没有起到实质性的作用,它们的作用仅仅是让请求传递下去,从性能方面考虑,我们要避 免过长的职责链带来的性能损耗。