以下代码会用到函数组合函数compose,只要知道compose是干什么的就足够了,如果好奇具体的实现,可以看《JavaScript函数式编程之函数组合函数compose和pipe的实现》
在写命令式的代码时,条件判断是经常使用的,经常会有如下类型的需求
if (isTrue) {
doSomething();
} else {
return;
}
比如表单验证
if (!validate1()) return;
if (!validate2()) return;
axios.post(...)
如果有一个验证没有通过,则停止运行,只有全部都通过才会发出请求,提交表单。
可当我们进行函数式编程时,这样的方式会遇到困难,难点在于如何停止。用上面命令式的代码,return了什么,return到了哪里,我们都不太需要关心。而在函数式编程中,数据在管道中流动,上一个函数的返回值会传给下一个函数,除非报错,事先写好的流程是停不下来的。这时,函数返回了什么,我们是一定要关心的。
同样的需求,用函数式的写法
let postData = () => axios.post(...);
let result = compose(postData, validate2, validate1);
我们同样希望有一个验证没有通过就立刻停止运行,可这是无法实现的,即使你在validate1里面写了一个return;
,这也只不过是停止了validate1的运行,而且还返回了一个undefined
传给了validate2。
那我们应该怎么做?
其实可以换一个思路
它要返回,就让它返回,只要返回值在我们的控制中,不用打断运行同样也可以达到目的。
let security = fn => val => val === null || val === undefined ? null : fn(val);
我们就可以用一个这样的函数来做安全验证,如果出现了验证失败,发现有空值,就返回一个null,如果正确就正常运行。
所以,之前的代码就可以这样改写,把可能会出错的地方全都包起来
let postData = () => axios.post(...);
let result = compose(security(postData), security(validate2), security(validate1));
首先传给validate1的值,如果是空,则返回空给下一步,下一步同样有security的安全验证,接到空值往下传递。
看到这里,是不是感觉这种思路有点熟悉?
我们在用express写路由的时候,通常会这样写
try {
doSomething();
} catch(err) {
next(err);
}
这个security方法与next(err)
就非常相似。
在写路由的时候,会有一个路由写在所有路由的最后,专门用来处理错误,借用这个思路,我们同样也可以在函数组合时根据自己的需要在方程的最后做一些保底的操作,例如
let handleError = x => {
if (!x) alert("errorMsg");
};
let result = compose(handleError, security(postData), security(validate2), security(validate1));
参考资料:
我在github
https://github.com/zhuanyongx...