这个承诺嵌套可以改为链接吗?

时间:2015-02-20 20:11:32

标签: javascript angularjs nested chaining angular-promise

这是伪方案

           | then (items)          | then (items, actions)
getItems() | getActions(for:items) | apply(actions -> items)
 :promise  |  :promise             | model <= items
           |                       |  :synchronous

所以用语言说:

  1. 我需要获取全球项目列表。
  2. 精细。提取的项目。
  3. 请求用户接管以前获取的项目的操作。
  4. 精细。提取的行动。
  5. 将操作应用于项目列表。
  6. 将项目放在模型上并在视图中显示。
  7. 这有点像我使用的代码

    return itemsResource
           .getItems(userId)
           .$promise
           .then(function(items) {
               return actionsResource
                      .getActions(items.map(i => i.id)) // pseudo mapper code here
                      .$promise
                      .then(function(actions) { // THIS IS NESTED so it sees both promise results
                          return [items, actions];
                      });
           })
           .then(helper.spread(function(items, actions) {
               applyActions(items, actions);
               $scope.model.items = items;
               return items;
           }));
    

    你可以理解我最初不能使用$q.all,因为第二个(行动)承诺取决于第一个(项目)的结果。

    为什么不通过项目返回操作?因为我为所有用户缓存了项目,所以项目提取非常快。这与Stackoverflow的工作方式类似。无论用户是否请求,他们都会返回问题。然后,他们随后还会请求首选和忽略的标签,并应用于提取的问题。这很好地扩展,否则SO将需要更多的服务器来处理所有用户的初始问题列表,因为每个用户的请求将产生不同的结果,因此缓存不太有意义。

    为什么不在提取后立即将项目应用到$scope这将消除额外的嵌套then,这是真的。但是我没有这样做,因为之后几乎没有其他步骤,每次一个承诺得到解决,至少有一个$digest周期正在执行。对于许多项目(相当复杂的对象),这可以解释相当多的处理。这就是我在最后一刻坚持将物品传递到视野的原因。

    问题

    除了这两种解决方法之外,有没有办法避免嵌套then

    1. 尽快将项目应用到$scope
    2. 将项目保存到本地变量并在之后使用
    3. 如果可能的话,我希望在不引入额外资源的情况下尽可能地展平我的代码?

2 个答案:

答案 0 :(得分:2)

除非我遗漏了什么,否则这应该是相当简单的,不是吗?

(为了清楚起见,我简化了一些内部功能签名)

itemsResource.getItems(userId)
  .then(function(items) {
    return $q.all({
      items: items,
      actions: actionResource.getActions(items)
    });
  })
  .then(function(data) {
    applyActions(data.items, data.actions);
    $scope.model.items = data.items;
    return data.items;
  });

plunker用于说明

答案 1 :(得分:0)

如何在promise中包含items-&gt;动作链的结果?像

这样的东西
return $q(function(resolve, reject) {

    var outerItems;

    itemsResource.getItems(userId).$promise
        .then(getActions)
        .then(function (actions) {
            resolve([outerItems, actions]);
        })
        .catch(function (err) { reject(err); });

    function getActions(items) {
        outerItems = items;
        return actionsResource.getActions(items).$promise
    }

}).then(function (itemAndActions) {
    var items = itemsAndActions[0], 
        actions = itemsAndActions[1];

    return helper.spread(function (items, actions) {
        applyActions(items, actions);
        $scope.model.items = items;
        return items;
    })
});