首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Javascript中,通过一系列承诺传递状态的模式是什么?

在Javascript中,通过一系列承诺传递状态的模式是什么?
EN

Stack Overflow用户
提问于 2014-04-06 10:16:15
回答 2查看 1.5K关注 0票数 9

我正在尝试学习一些关于Node和异步编程的知识。我读到了有关承诺的文章,并尝试在一个小项目中使用它们,该项目将用户的帖子从服务A复制到服务B。我很难理解如何最好地在承诺之间传递状态。

该项目是使用NodeJS为允诺库编写的。

我目前问题的一个简单定义是:

  • 如果服务B中不存在用户的帖子,则将用户的帖子从服务A复制到服务B。
  • 这两个服务都提供了http API,需要一个不值得记忆的用户id来查找该用户的帖子,因此必须从用户名中查找用户id。
  • 所有的http调用都是异步的。

这是一些伪代码,说明了我是如何将承诺链接在一起的。

代码语言:javascript
运行
复制
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); 
  });

我想做几件事:

  1. 将getIdForUsername调用引入getPostsForUserId函数中。然而,我希望按照‘做一件事并做好它’的原则,使每个功能单元尽可能简单。
  2. 创建一个“上下文”对象,并将其传递到整个链中,读取并存储该对象中的状态。然而,,这种方法使每个函数都非常适合于一个链,因此很难单独使用。

还有其他选择吗?建议采用什么方法?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-04-06 10:37:17

我会用Promise.all,就像这样

代码语言:javascript
运行
复制
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
    });
票数 3
EN

Stack Overflow用户

发布于 2014-04-06 13:35:29

首先是个好问题。这是我们(至少我)经常处理的事情。在我看来,这也是一个承诺真正超越了回调的地方。

这里所做的基本上是,你真正想要的是你的图书馆没有的两样东西:

  1. .spread,它接受返回数组并将其从数组参数更改为参数的承诺。这允许将像.then(result) { var postsA = result[0], postsB = result[1];这样的东西切割到.spread(postsA,postsB中。
  2. .map,它获取一个承诺数组,并将数组中的每个承诺映射到另一个承诺--它类似于.then,但对于数组的每个值。

有两个选项,要么使用已经像蓝鸟那样使用它们的实现,因为它比现在的替代方案(更快、更好的堆栈跟踪、更好的支持、更强大的特性集)要好得多,要么可以实现它们。

由于这是一个答案,而不是一个库推荐,所以让我们这样做:

让我们从扩展开始,这相对容易--这意味着调用Function#apply将数组扩展到varargs。下面是一个示例实现i 偷了我自己的东西:

代码语言:javascript
运行
复制
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基本上只是数组映射,然后:

代码语言:javascript
运行
复制
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来启动链:

代码语言:javascript
运行
复制
Promise.map = function(arr,mapping){
     return Promise.resolve(arr).map(mapping);
};

现在,我们可以像实际想要的那样编写您的代码:

代码语言:javascript
运行
复制
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几乎从来没有。像蓝鸟这样的可靠库可以显着地减少代码。您正在使用的承诺库,甚至在它们的文档中都这样说:

它的设计是为了使基础点正确,这样您就可以在其之上构建扩展的承诺实现。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22892681

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档