Angularjs:我怎样才能使服务代码“看起来同步”?

时间:2014-09-24 08:24:44

标签: angularjs asynchronous promise angular-promise

如何制作Angular服务代码"看起来是同步的"?

当我清理控制器并将业务逻辑代码放入服务中时,我的问题出现了。到现在为止还挺好。现在我想等待"在服务函数中,直到所有异步调用都返回并且然后返回。我怎么能这样做?

为了说明我的问题,假设你有一个只有的控制器代码:

  1. 从后端请求一些数据
  2. 使用数据和
  3. 进行一些处理
  4. 将数据交给范围
  5. 就像那样:

    重构前的

    DataController:

    $scope.submitForm = function() {
    
        RestBackend.query('something').then(function(data) {
    
            // do some additional things ...
            ...
    
            $scope.data = data;
        });
    };
    

    非常简单。获取数据并填充范围。

    在重构为控制器+服务之后,我最终得到了:

    DataController重构:

    $scope.submitForm = function() {
    
        DataService.getData().then(function(data) {
            $scope.data = data;
        });
    };
    

    DataService重构:

    this.query = function() {
        var dataDefer = $q.defer();
    
        RestBackend.query('something').then(function(data) {
    
            // do some additional things ...
            ...
    
            dataDefer.resolve(data);
        });
        return dataDefer.promise;
    };
    

    我不喜欢我必须在控制器中使用承诺的事实。我喜欢承诺,但我想让控制器不知道这个"实现细节"的服务。这就是我希望控制器代码看起来像:

    DataController(应该如此):

    $scope.submitForm = function() {
    
        $scope.data = DataService.getData();
    };
    

    你明白了吗?在控制器中,我不想关心承诺与否。只需等待获取数据然后使用它。因此,我正在寻找实现这样的服务的可能性:

    1. 查询数据(异步)
    2. 在获取数据之前不返回
    3. 返回提取的数据
    4. 现在第2项对我来说不清楚:我怎样才能等到数据被提取出来"然后才继续?目标是服务功能看起来是同步的。

3 个答案:

答案 0 :(得分:2)

我也认为你的解决方案很好 返回承诺不是服务的实现细节。它是服务API的一部分("合同"服务和服务 - 消费者之间)。

控制器需要一个与数据一起解析的承诺,并根据需要处理它 如何构建承诺,如何获取数据等,这些都是实现细节 您可以随时将服务交换为完全不同的服务,只要它履行合同(即返回一个随数据准备就绪的承诺)。


也就是说,如果您只使用视图中的数据(即在获取后不立即在控制器中直接操作它),这似乎就是这种情况,您可以使用ngResources方法:< / p>

返回一个空数组,并在获取数据后用数据填充它:

$scope.data = DataService.getData();

// DataService refactored:
this.getData = function () {
    var data = [];

    RestBackend.query('something').then(function(responseData) {
        // do some additional things ...
        ...
        angular.forEach(responseData, function (item) {
            data.push(item);
        });
    });

    return data;
};

顺便说一下,在当前(精细)设置中,您需要$q.defer()。你可以使用promise-chaining:

this.query = function() {
    return RestBackend.query('something').then(function(data) {
        // do some additional things ...
        ...
        return data;
    });
};

答案 1 :(得分:1)

我认为你所拥有的是一个非常好的解决方案。你不应该等待承诺得到解决,它会失去async javascript的目的。只要问问自己为什么需要让它同步运行?

如果你依赖html承诺得到解决,你可以做这样的事情

<div class="alert alert-warning text-center" data-ng-hide="!data.$resolved">
   Got data from service.
</div>

答案 2 :(得分:1)

当您使用ngRoute时,我建议您在路由配置中解析数据,并且一旦所有数据将加载视图得到解决。

$routeProvider
  .when('/your-url', {
    templateUrl: 'path/to/your/template.html',
    controller: 'YourCtrl',

    // that's the point !
    resolve: {
      superAwesomeData: function (DataService) {
        return DataService.getData();
      }
    }
  });

现在,superAwesomeData可以在您的控制器中注入,它将包含已解决的数据。

angular.module('youModule')
  .controller('YourCtrl', function (superAwesomeData) {

    // superAwesomeData === [...];

  });