天,请注意时效性
最近在看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 |
|