天,请注意时效性
最近在看Promise相关的东西,看到了这篇文章,觉得很不错,遂记录下来。
Promises本身是很简单的,前提是你得找得到头绪,下面是几个关于 Promise 的容易困惑的知识点来验证你是否真的掌握了Promise。其中的几个真的曾经让我抓狂过。
嵌套 Promises
你有一捆的 Promises 互相嵌套着:
1 | |
你这么做的原因是你需要处理这两个 Promises 的结果,所以你不能链式调用他们因为then()方法只接受上一个then()返回的结果。(意思是这两个Promise是需要同时处理没有先后关系的,但是then却有个先后关系,如果前者throw error直接进入catch处理环节)
呵呵,其实你这么写的真正原因是你不知道all()方法:
解决这种丑陋写法的方案:
1 | |
更简洁了。q.all()返回一个promise对象,并将这个结果结合成一个数组并传递给resolve方法供之后的then方法调用,spread()方法将会分割这个数组为几个数组长度的参数传递给其中的DoSomethingOnThem函数。
(注:Promise.all()接受一个数组作为参数,数组元素为promise,元素之前没有先后顺序,同时执行,最后传递给then方法的值为各个promise方法return值的数组。这里作者使用的是node中的一个模块q作为示例)
中断的链式调用
假设你有这样一段代码:
1 | |
这段代码的问题是,出现在somethingComplicated()函数的error都不会被捕获。Promises意味着能够链式调用(不然还叫什么then,直接done就行了)每一个被调用的then()方法返回一个新的promise,这个新的promise是会被下一个then()方法继续调用的。正常来说,最后一个调用应该是catch()方法,出现在链式调用任何地方的任何error都会被它捕获并处理。
在上面的的代码中,链式调用在你返回第一个promise而不是返回一个then处理后的新的的promise给最后一个then调用的时候中断了(即then不改变原有的promise,它只处理它,然后返回一个新的promise)。
解决这个问题的方案:
1 | |
记住,总是返回最后一个then()的结果(以能够使用链式调用)。
混乱的集合
你有一组元素的数组,你想对这个数组的每个元素之执行一些异步操作。所以你发现你需要做一些涉及到递归调用的事情。
1 | |
额。。这段代码不是很直观,问题的关键在与,当你不知道有多长的链式调用的时候,链式调用就变成一个意见痛苦的事情。除非你知道(JavaScript ES5+原生的数组方法)map()和reduce()
解决方案:
记住,q.all参数是一个由promise构成的数组,同时它会把结果放到一个数组中并传给resolve方法。我们可以简单的使用数组元素的 map 方法来对每个数组中的元素执行这个异步调用方法,像下面这样:
1 | |
不像开始那个并不是什么解决方案的递归调用,这段代码将同步调用数组中的每个元素传递给一个异步调用函数。明显在时间上更有效率一些。
如果你需要按顺序返回promises,你可以使用reduce:
1 | |
看起来不是很简单明了,但是确实比最开始的那个简洁多了。(Not quite as tidy, but certainly tidier.)
幽灵 Promise
有一个确定的方法(意思是已经在开始执行 Promise 时就给出此方法,而不是在执行中由结果来确定的方法—译者注),有时候需要异步调用,有时候又不需要。因此你为了应对这两种情况只创建了一个 promise 仅仅是为了保持异步和非异步的情况下代码一致(以便于抽象和解耦—译者注),即使这种情况实际只可能出现其中一种。
1 | |
以上这段代码在反面模式中并不算最糟糕的地方,但是却应该写的更清晰一些—用Q()来包裹value或promise。Q()方法即接受一个值也接受一个promise作为参数:
1 | |
备注:开始的时候我在这个情况下建议使用Q.when(),多亏了 Kris Kowal 同学在评论中的建议把我从错误中拯救出来。不要使用Q.when(),只使用Q()就够了,后者更清晰一些。
饥渴的错误处理函数
小节标题意思是在
then中同时设置fulfilled和rejected,以期能够使用rejected函数处理同样作为then函数参数的fulfilled中的错误,但是这是不可能的,fulfilled中的error只能传递给下一个then()而不能在当前被rejected函数处理,所以这小节的标题为『过度渴望』—它虽然渴望处理错误,但是错误永远不会传递给它让他处理—译者注
then()方法接受两个参数,对fulfilled状态的操作函数和对rejected状态操作函数。你可能写过下面这种代码:
1 | |
这么写的问题是,发生在fulfilled状态的的error不会传递给错误处理函数。
解决这个问的的方法是,确保错误处理函数在一个独立的 then 方法中:
1 | |
或者使用catch():
1 | |
这样可以确保任何发生在链式调用中的error都能得到处理。
被遗忘的 Promise
你调用一个方法,返回一个promise,然而你忘记了这个promise,然后又创建了一个promise:
1 | |
这段代码真的是把promsie的简洁特性抛弃的一干二净—有太多无用的代码了。
解决方案是,仅仅返回promise即可:
1 | |
我常常希望在面对人生中一些关键抉择的时候,有人可以告诉我最佳的做法,让我不至于白白浪费宝贵的时间。推己及人,我因此经常写博客,以期在浩渺无垠的互联网中的这个小小角落里记录下对于我来说只有一次的人生经历,希望能够帮到那些希望得到帮助的人。