控制器进行多个同步嵌套服务调用

时间:2017-05-04 23:08:25

标签: javascript angularjs

在下面的简单示例中,我有一个方法调用(getMoreProducts),需要在第一个方法调用(getProducts)完成后调用。

由于我是angularjs的新手(并且对JS来说还是新手),我想确认是否有其他方法可以实现这一目标。我担心的是,如果需要在getMoreProducts之后调用另一种方法,那么代码将是三级深度,依此类推。

.controller('ProductController',function(ProductService, $scope){
  $scope.products = [];
  $scope.moreProducts  = [];

  ProductService.getProducts().then(function(res){
     $scope.products = res.data;

     ProductService.getMoreProducts().then(function(res){
        $scope.moreProducts = res.data;
     });
  });

对于此示例,假设ProductService方法只是调用HTTP GET调用。

2 个答案:

答案 0 :(得分:1)

OP中嵌套承诺中使用的反模式是一种“回调地狱”形式,这正是承诺应该帮助的形式。

当下次通话取决于之前的通话时,保证应该串联,这样它们的深度不会超过1级:

  ProductService.getProducts().then(function (productsRes) {
     $scope.products = productsRes.data;
     return ProductService.getMoreProducts();
  })
  .then(function (moreProductsRes) {
      $scope.moreProducts = moreProductsRes.data;
     return ProductService.getEvenMoreProducts();
  })
  .then(function (evenMoreProductsRes) { ... });

当承诺不依赖于彼此的结果时(例如在这种情况下),它们可以并行执行,这就是$q.all的用途:

$q.all([ProductService.getProducts(), ProductService.getMoreProducts()])
.then(function (responses) {
   var productsRes = responses[0];
   var moreProductsRes = responses[1];
   $scope.products = productsRes.data;
   $scope.moreProducts = moreProductsRes.data;
});

答案 1 :(得分:0)

是的,您可以利用承诺链。如果你在另一个中返回一个承诺,你可以避免讨厌的嵌套:

var app = angular.module('plunker', []);


// Before
app.controller('MainCtrl', function($scope, ProductService) {
  $scope.name = 'World';

  $scope.products = [];
  $scope.moreProducts  = [];

  ProductService.getProducts().then(function(res){
    $scope.products = res.data;

    ProductService.getMoreProducts().then(function(res){
        $scope.moreProducts = res.data;
    });
  });
});

// After with promise chaining
app.controller('MainCtrl', function($scope, ProductService) {
  $scope.name = 'World';

  $scope.products = [];
  $scope.moreProducts  = [];

  ProductService.getProducts().then(function(res){
    $scope.products = res.data;
    return ProductService.getMoreProducts()
  })
  .then(function(res){
      $scope.moreProducts = res.data;
  });
});


app.service('ProductService', function($timeout){
  this.getProducts = function() {
    return $timeout(function(){
      return {
        data: [{name: 'Widget', color: 'blue'}]
      }
    }, 500)
  }

  this.getMoreProducts = function() {
    return $timeout(function(){
      return {
        data: [{name: 'Widget', color: 'green'}, {name: 'Widget', color: 'red'}]
      }
    }, 1000)
  }
})

根据getProductsgetMoreProducts调用的要求,您可以使用参数而不是使用不同的函数。

http://plnkr.co/edit/K4LPKWSD06QnwbRk8k0B?p=preview

编辑:

顺便说一句,我不推荐这种创建控制器和服务的方式,它只是默认的plunker模板。

请参阅Y021 Y022 Y031