您的位置:首页 > 其它

如何优雅的处理 Promise 的 if-else 分支

2017-03-12 18:09 459 查看
本文总计 1659 字,阅读大概需要 15 分钟。

疑问

为了解决丑陋的回调问题,基本上 Promise 已经成为标配。但是当 Promise 遇到 if-else分支,需要走不同的链时如何处理?
举个栗子

if true


 .then(do1())


 .then(do2())


 .then(do3())


 .then(do4())


else


 .then(do2())


 .then(do3())


.then(do5())


这样的话用 Promise 怎么处理更优雅?

解答

当 Promise 遇到 if-else分支总感觉不伦不类。因为 javascript 拥抱函数式编程的同时又不得不考虑到自己是命令式语言。
javascript 宣称自己可以面向对象、面向过程、面向函数。言外之意就是,厉害吧。而现实是,大部分 JSer 都在混合式编程,不伦不类,不三不四。
回到上面的问题:首先在写法上 
.then(do1()).then(do2())
 就是错误的,正确的写法应该是 
.then(do1).then(do2)
——传入的是函数,而不是函数调用后的返回值。
另一方面,对比一下如下代码:

fn(true) { do1(); }


if(true) { do1(); }


除了 
fn
 和 
if
 两个单词之外,其它代码都相同。这两行代码如此的相似,但是却有着本质的区别。
有人可能会说这是废话,一个是函数,一个是 
if
,当然不一样了啊。其实,这种区别只限于类 javascript 语言,在某些语言中,两者是没有任何区别的。
如果我们深入的研究这两者的区别,那就有意思了。。。
几年前我写过一篇博文,代码之谜(二)- 语句与表达式。对,他们的区别就在于,在 javascript 中, 
fn(true){do1();}
 是表达式,而 
if(true){do1();}
 是语句。
表达式都有自己的值,而语句没有。因此我们可以写:

f = fn(true) { do1(); }


但是不能写:

f = if(true) { do1(); }


但是你千万不要把它看作是理所当然的。在某些语言,尤其是函数式编程语言中,if-else也是表达式,就如同 
m=1+2
,就如同 
add(3,9)
。很多函数式编程语言的卖点就是只有表达式,没有语句。比如 Kotlin 中,你可以这么写:

val max = if (a > b) a elseb


如果你在 javascript 中这么写的话,就报错了。
回到原始问题,如果我们不使用 if-else语句,而是使用表达式,那么这个问题就迎刃而解了。我们可以定义 
pIf
、 
pElse
 函数专门用于 promise。也可以定义一个对象,把 
if
、 
else
 作为对象的属性(因为 javascript 的对象 key 都是字符串,因此可以使用 javascript 的关键字作为键名)。
如果我们使用 promise-conditional 库,写出来的代码是这样的:

doSomething()


 .then(conditional()


   .if(data => data.length > 10)


     .then(doIfTrue)


     .then(alsoDoIfTrue)


   .elseIf(data => data.length > 5)


     .then(doIfTrue)


   .else()


     .then(doIfFalse)


   .end())


如果你不喜欢对象风格,喜欢函数风格的话,可以试试 p-if 库。
忘掉语句,拥抱表达式,享受函数式编程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: