【问题标题】:Angular $q promises and non-linear chainingAngular $q 承诺和非线性链接
【发布时间】:2016-09-23 10:28:39
【问题描述】:

大家好。我撞到了一堵砖墙。我正在尝试研究 Angular 异步方法调用、承诺对象并实现特定问题的解决方案。经过几个小时的反复试验和重组我的代码,我确信现在答案就在我的眼皮底下,但我看不到它。

我有一个场景,我必须使用 $http 进行后端服务调用,这会产生一个承诺。在 promise 的结果中,我将收到一个具有一个字符串属性和一个包含 100 个 ID 的数组的数据对象。这个后端服务一次只会传递 100 个 ID 的有效负载,所以我必须进行 x 次 $http 调用才能到达列表的末尾,正如这个后端服务所提供的那样。据我了解,我必须在 promise 的 .then() 方法中评估 $http 响应,如果字符串属性为“N”,那么我知道我必须再次调用后端服务以获取另一批 100 个 ID。在所有 ID 都已交付后,该字符串将包含一个“Y”,表示此结束已发送并且不再调用。不需要对这个计划发表评论,我知道它相当蹩脚,不幸的是我无法控制。 ;-)

如果需要更多的异步调用,我所研究的关于 Promise 的所有内容似乎都以线性方式说明了 Promise 的链接。无论承诺链是嵌套的还是扁平的,似乎我只能进行“已知”或固定数量的顺序调用,例如Promise1 到 Promise2,到 Promise3 等。请原谅我对这里的承诺的有限经验。

这是一个代码示例,你可以看到我卡在这里的地方,向下嵌套。我不能只是“希望”在打了 3 次、5 次或 10 次电话后我会得到所有的 ID。我需要动态评估每次调用的结果并再次调用。

这里是调用 $http 的 Angular 服务

(function() {
'use strict';

  angular
      .module('myapp')
      .factory('IDservice', IDservice);

  function IDservice($http) {

    var service = {
    model: {
        error: {
          state: false,
          message: ''
        },
        ids: [],
        end: '',
      },
      GetIDs: function() {
        var request = 'some params...';
        var url = 'the url...';
        return $http.post(url, request).then(reqComplete).catch(reqFailed);

        function reqComplete(response) {
          service.model.ids = response.data.idList;
          service.model.end = response.data.end;
          return service.model;
        }

        function getIntradayMsrFailed(error) {
          service.model.error.state = true;
          service.model.error.message = error;
          return service.model;
        }

      }
    };
    return service;
  }

})();

这里是调用 Angular 服务的控制器,它最终在各个视图上驱动一些 UI 元素:

(function() {
  'use strict';

  angular
    .module('myapp')
    .controller('AvailableIDsController', AvailableIDsController);

  function AvailableIDsController($scope, $location, $timeout, IDservice) {
    var vm = this;
    vm.completeIDList = [];

    activate();    

    function activate() {
        IDservice.GetIDs().then(function(response){
          vm.completeIDList = response.ids;
          console.log('promise1 end');
            if(response.end === 'N'){
              IDservice.GetIDs().then(function(response){
                angular.forEach(response.ids,function(nextID){
                  vm.comleteIDList.push(nextID);
                 });
                console.log('promise2 end'); 
                if(response.end === 'N'){
                  IDservice.GetIDs().then(function(response){
                    angular.forEach(response.ids,function(nextID){
                      vm.comleteIDList.push(nextID);
                    });
                    console.log('promise3 end');
                  });   
                }
             });    
           }
        });         

     console.log('mainthread end');
     }
}
})();

你可以看到它的去向......而且它非常非常丑陋。

我需要一种方法,在 activate() 方法中,调用一个方法,该方法将负责调用服务调用并将结果返回给 activate()。现在,仍然在 activate() 方法中,评估结果并确定是否再次调用,等等。我卡住的地方是一旦主处理线程完成,你就可以在第一个承诺中获得程序控制。从那里,您可以执行另一个承诺,等等,然后沿着兔子洞走。一旦我陷入这个陷阱,一切都将丢失。很明显我做的不对。我错过了其他一些简单的难题。任何建议将不胜感激!

【问题讨论】:

标签: javascript angularjs asynchronous promise angular-promise


【解决方案1】:

您正在寻找普通的旧递归:

function AvailableIDsController($scope, $location, $timeout, IDservice) {
    var vm = this;
    vm.completeIDList = [];
    return activate(0);    

    function activate(i) {
        return IDservice.GetIDs().then(function(response) {
            [].push.apply(vm.completeIDList, response.ids); // simpler than the loop
            console.log('promise'+i+' end');
            if (response.end === 'N'){
                return activate(i+1);
            }
        });
     }
}

不要忘记returns,这样 Promise 会链接在一起,您可以等待请求结束。

【讨论】:

  • Bergi,感谢您的评论和解决方案。它工作得很好!非常感谢:-)
猜你喜欢
  • 2015-04-15
  • 2023-03-14
  • 1970-01-01
  • 2015-02-04
  • 1970-01-01
  • 1970-01-01
  • 2016-06-21
  • 2017-03-18
  • 2015-05-12
相关资源
最近更新 更多