这个promise嵌套可以改为链接吗

Can this promise nesting be changed to chaining?

本文关键字:链接 promise 嵌套 这个      更新时间:2024-02-11

这是伪场景

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

所以用文字来说:

  1. 我需要一份全局项目列表
  2. 很好。已提取项目
  3. 请求用户对以前提取的项目执行的操作
  4. 很好。已提取操作
  5. 将操作应用于项目列表
  6. 将项目放在模型上并在视图中显示

这是我使用的代码

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,这是真的。但我不会这么做,因为之后还有几个步骤,每次解决其中一个promise时,至少会执行一个$digest循环。对于许多项目(相当复杂的对象),这可能会导致相当多的处理。这就是我坚持把项目传递到视图的最后一刻的原因。

问题

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

  1. 尽快将项目应用于$scope
  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

将items->操作链的结果包装在promise中如何?类似的东西

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;
    })
});