我正在尝试学习一些关于Node和异步编程的知识。我读到了有关承诺的文章,并尝试在一个小项目中使用它们,该项目将用户的帖子从服务A复制到服务B。我很难理解如何最好地在承诺之间传递状态。
该项目是使用NodeJS为允诺库编写的。
我目前问题的一个简单定义是:
这是一些伪代码,说明了我是如何将承诺链接在一起的。
Promise.from('service_A_username')
.then(getServiceAUserIdForUsername)
.then(getServiceAPostsForUserId)
.then(function(serviceAPosts) {
// but what? store globally for access later?
doSomethingWith(serviceAPosts);
return Promise.from('service_B_username');
})
.then(getServiceBUserIdForUsername)
.then(getServiceBPostsForUserId)
.done(function(serviceBPosts) {
// how do we interact with Service A posts?
doSomethingThatInvolvesServiceAPostsWith(serviceBPosts);
});
我想做几件事:
还有其他选择吗?建议采用什么方法?
发布于 2014-04-06 02:37:17
我会用Promise.all
,就像这样
Promise.all([Promise.from('usernameA'), Promise.from('usernameB')])
.then(function(result) {
return Promise.all([getUsername(result[0]),getUsername(result[1])])
})
.then(function(result) {
return Promise.all([getPosts(result[0]),getPosts(result[1])]);
})
.then(function(result) {
var postsA = result[0], postsB = result[1];
// Work with both the posts here
});
发布于 2014-04-06 05:35:29
首先是个好问题。这是我们(至少我)经常处理的事情。在我看来,这也是一个承诺真正超越了回调的地方。
这里所做的基本上是,你真正想要的是你的图书馆没有的两样东西:
.spread
,它接受返回数组并将其从数组参数更改为参数的承诺。这允许将像.then(result) { var postsA = result[0], postsB = result[1];
这样的东西切割到.spread(postsA,postsB
中。.map
,它获取一个承诺数组,并将数组中的每个承诺映射到另一个承诺--它类似于.then
,但对于数组的每个值。有两个选项,要么使用已经像蓝鸟那样使用它们的实现,因为它比现在的替代方案(更快、更好的堆栈跟踪、更好的支持、更强大的特性集)要好得多,要么可以实现它们。
由于这是一个答案,而不是一个库推荐,所以让我们这样做:
让我们从扩展开始,这相对容易--这意味着调用Function#apply
将数组扩展到varargs。下面是一个示例实现i 偷了我自己的东西:
if (!Promise.prototype.spread) {
Promise.prototype.spread = function (fn) {
return this.then(function (args) {
//this is always undefined in A+ complaint, but just in case
return fn.apply(this, args);
});
};
}
接下来,让我们来做映射。承诺上的.map
基本上只是数组映射,然后:
if(!Promise.prototype.map){
Promise.prototype.map = function (mapper) {
return this.then(function(arr){
mapping = arr.map(mapper); // map each value
return Promise.all(mapping); // wait for all mappings to complete
});
}
}
为了方便起见,我们可以引入静态的.map
来启动链:
Promise.map = function(arr,mapping){
return Promise.resolve(arr).map(mapping);
};
现在,我们可以像实际想要的那样编写您的代码:
var names = ["usernameA","usernameB"]; // can scale to arbitrarily long.
Promise.map(names, getUsername).map(getPosts).spread(function(postsA,postsB){
// work with postsA,postsB and whatever
});
这就是我们一直想要的语法。没有代码重复,它枯燥,简洁,清晰,承诺的美。
请注意,这并没有触及蓝知更鸟所做的事情的表面--例如,蓝鸟会检测到它是一个地图链,并且在没有完成第一个请求的情况下将函数“推送”到第二个请求上,所以第一个用户的getUsername
不会等待第二个用户,但是如果更快的话,实际上会调用getPosts
,所以在这种情况下,它与您自己的gist版本一样快,而imo更清晰。
然而,它是有效的,是不错的。
简单的A+实现更适合于承诺库之间的互操作性,并且应该是一个“基线”。在设计特定平台时,它们是有用的--小APIs - IMO几乎从来没有。像蓝鸟这样的可靠库可以显着地减少代码。您正在使用的承诺库,甚至在它们的文档中都这样说:
它的设计是为了使基础点正确,这样您就可以在其之上构建扩展的承诺实现。
https://stackoverflow.com/questions/22892681
复制相似问题