And*_*ton 9 javascript asynchronous chaining node.js promise
我正在尝试学习一些关于Node和异步编程的知识.我读到了Promises,并试图在一个小项目中使用它们,这个项目将用户的帖子从服务A复制到服务B.我在理解如何最好地在Promises之间传递状态时遇到一些麻烦
该项目是使用Promise库为NodeJS编写的
我当前问题的一个简单定义是:
这是一些伪代码,说明了我如何将Promise链接在一起.
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);
});
Run Code Online (Sandbox Code Playgroud)
我想过要做的一些事情:
还有其他选择,建议采用什么方法?
首先是好问题.这是我们(至少我)经常处理承诺的事情.在我看来,它也是一个承诺真正超越回调的地方.
这里发生的事情基本上是你真的想要你的图书馆没有的两件东西:
.spread它接受一个返回数组并将其从数组参数更改为参数的promise.这使得切割之类的东西.then(result) { var postsA = result[0], postsB = result[1];进入.spread(postsA,postsB.
.map它接受一个promises数组并将数组中的每个promise映射到另一个promise - 就像.then数组的每个值一样.
有两个选项,要么使用已经使用它们的实现,就像我推荐的Bluebird一样,因为它比现在的替代品要好得多(更快,更好的堆栈跟踪,更好的支持,更强大的功能集)或者你可以实现它们.
既然这是一个答案而不是图书馆推荐,那就让我们这样做:
让我们从传播开始,这是相对容易的 - 所有这意味着调用Function#apply将数组传播到varargs.以下是我自己偷走的示例实现:
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);
});
};
}
Run Code Online (Sandbox Code Playgroud)
接下来,我们来做映射..map在promises上基本上只是一个带有a的数组映射:
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
});
}
}
Run Code Online (Sandbox Code Playgroud)
为方便起见,我们可以引入一个静态对应物.map来启动链:
Promise.map = function(arr,mapping){
return Promise.resolve(arr).map(mapping);
};
Run Code Online (Sandbox Code Playgroud)
现在,我们可以像我们想要的那样编写代码:
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
});
Run Code Online (Sandbox Code Playgroud)
这是我们一直想要的语法.没有代码重复,它是干的,简洁明了,承诺的美丽.
请注意,这并不会划伤Bluebird所做的事情 - 例如,Bluebird将检测到它是一个地图链并将"推送"功能打开到第二个请求,而第一个请求甚至完成,因此getUsername第一个用户赢了"等待第二个用户,但实际上会调用,getPosts如果这更快,所以在这种情况下,它与你自己的要点版本一样快,同时更清晰的imo.
但是,它工作正常,很好.
Barebones A +实现更多用于promise库之间的互操作性,并且应该是一个"基线".它们在设计特定平台小型API时很有用 - IMO几乎从不.像Bluebird这样的可靠库可以显着减少您的代码.您正在使用的Promise库,甚至在他们的文档中说:
它旨在使基础知识正确,以便您可以在其上构建扩展的承诺实现.
我会用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
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1353 次 |
| 最近记录: |