popmotion 设计篇3 :返回值

在上一篇中,我们设计出了这样一种动作类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class Action{
constructor(props){
this.props=props;
// this.props.do 是一个算法框架函数
// this.props.middlewares 是一个中间件数组
}

// 这里为了直观,我们直接修改当前对象,
// todo: 改为创建一个新对象,让代码更函数式
filter(predicate){

// 自定义一个用于转换的中间件
let mw=(update,complete,error)=>{
return {
"update": (v)=>{
if(predicate(v)) update(v);
},
"complete": complete,
"error": error
},
};

this.props.middlewares.push(mw);
}

/**
* 根据executor和自身的middlewares合成新的函数对象
*/
_produce(executor){
let {
update = (v)=>{},
complete =()=>{},
error=()=>{},
}=executor;

let middlewares=this.props.middlewares;

for(let i=0;i<middwares.length;i++){
let mw=this.middlewares[i];
let r=mw(update,complete,error);
update=r.update;
complete=r.complete;
error=r.error;
}

return {update,complete, error };
}

start(executor){
let {do}=this.props;

let {update,complete,error}=this._produce(executor);

do(update,complete,error);
}
}

注意到start(executor)方法中,我们只是简单调用了算法框架do(update,complete,error),为什么不顺带返回算法框架的返回值?

1
2
3
4
5
6
7
8
9
10
11
class Action{
constructor(props){
this.props=props;
}

start(executor){
let {do}=this.props;
let {update,complete,error}=this._produce(executor);
return do(update,complete,error);
}
}

这样的话,start(executor)就可以返回算法框架在具体executor下执行的结果,为进一步自定义API提供了更多的可能,比如:

1
2
3
4
5
6
7
8
9
10
11
const oneEverySecond = action(({ update }) => {
const updateOne = () => update(1);
const interval = setInterval(updateOne, 1000);

return {
stop: () => clearInterval(interval)
};
});

const foo = oneEverySecond.start();
setTimeout(() => foo.stop(), 3000); // 1, 1, 1