Angularjs:我如何制作服务代码;看起来是同步的;?

Angularjs:我如何制作服务代码;看起来是同步的;?,angularjs,asynchronous,promise,angular-promise,Angularjs,Asynchronous,Promise,Angular Promise,如何使角度服务代码“看起来是同步的” 当我清理控制器并将业务逻辑代码放入服务中时,我的问题出现了。到现在为止,一直都还不错。现在我想在服务函数中“等待”,直到所有异步调用都返回,然后返回。我该怎么做 为了说明我的问题,假设您有一个控制器代码,它只是: 从后端请求一些数据 对数据和数据进行一些处理 将数据交给范围 就像这样: 重构前的DataController: $scope.submitForm = function() { RestBackend.query('something'

如何使角度服务代码“看起来是同步的”

当我清理控制器并将业务逻辑代码放入服务中时,我的问题出现了。到现在为止,一直都还不错。现在我想在服务函数中“等待”,直到所有异步调用都返回,然后返回。我该怎么做

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

  • 从后端请求一些数据
  • 对数据和数据进行一些处理
  • 将数据交给范围
  • 就像这样:

    重构前的DataController:

    $scope.submitForm = function() {
    
        RestBackend.query('something').then(function(data) {
    
            // do some additional things ...
            ...
    
            $scope.data = data;
        });
    };
    
    $scope.submitForm = function() {
    
        DataService.getData().then(function(data) {
            $scope.data = data;
        });
    };
    
    this.query = function() {
        var dataDefer = $q.defer();
    
        RestBackend.query('something').then(function(data) {
    
            // do some additional things ...
            ...
    
            dataDefer.resolve(data);
        });
        return dataDefer.promise;
    };
    
    $scope.submitForm = function() {
    
        $scope.data = DataService.getData();
    };
    
    很简单。获取数据并填充范围

    在重构到controller+服务之后,我最终得到了:

    数据控制器重构:

    $scope.submitForm = function() {
    
        RestBackend.query('something').then(function(data) {
    
            // do some additional things ...
            ...
    
            $scope.data = data;
        });
    };
    
    $scope.submitForm = function() {
    
        DataService.getData().then(function(data) {
            $scope.data = data;
        });
    };
    
    this.query = function() {
        var dataDefer = $q.defer();
    
        RestBackend.query('something').then(function(data) {
    
            // do some additional things ...
            ...
    
            dataDefer.resolve(data);
        });
        return dataDefer.promise;
    };
    
    $scope.submitForm = function() {
    
        $scope.data = DataService.getData();
    };
    
    数据服务重构:

    $scope.submitForm = function() {
    
        RestBackend.query('something').then(function(data) {
    
            // do some additional things ...
            ...
    
            $scope.data = data;
        });
    };
    
    $scope.submitForm = function() {
    
        DataService.getData().then(function(data) {
            $scope.data = data;
        });
    };
    
    this.query = function() {
        var dataDefer = $q.defer();
    
        RestBackend.query('something').then(function(data) {
    
            // do some additional things ...
            ...
    
            dataDefer.resolve(data);
        });
        return dataDefer.promise;
    };
    
    $scope.submitForm = function() {
    
        $scope.data = DataService.getData();
    };
    
    我不喜欢这样一个事实,即我必须在控制器中也有承诺。我喜欢承诺,但我想让控制器不知道服务的“实现细节”。这就是我希望控制器代码的样子:

    DataController(应该是):

    $scope.submitForm = function() {
    
        RestBackend.query('something').then(function(data) {
    
            // do some additional things ...
            ...
    
            $scope.data = data;
        });
    };
    
    $scope.submitForm = function() {
    
        DataService.getData().then(function(data) {
            $scope.data = data;
        });
    };
    
    this.query = function() {
        var dataDefer = $q.defer();
    
        RestBackend.query('something').then(function(data) {
    
            // do some additional things ...
            ...
    
            dataDefer.resolve(data);
        });
        return dataDefer.promise;
    };
    
    $scope.submitForm = function() {
    
        $scope.data = DataService.getData();
    };
    
    你明白了吗?在控制器中,我不想关心承诺与否。只需等待获取数据,然后使用它。因此,我正在寻找实现以下服务的可能性:

  • 查询数据(异步)
  • 在获取数据之前不要返回
  • 返回获取的数据

  • 现在是项目2。我不清楚:我怎么能“等到数据被提取”然后才继续?我们的目标是使服务功能看起来是同步的。

    我认为您拥有的是一个非常好的解决方案。您不必等待承诺得到解决,它违背了异步javascript的目的。问问自己,为什么需要让它同步运行

    如果您在html中依赖于promise to be resolve,那么您可以这样做

    <div class="alert alert-warning text-center" data-ng-hide="!data.$resolved">
       Got data from service.
    </div>
    
    
    从服务中获取数据。
    
    我也认为您的解决方案很好。
    返回承诺不是服务的实现细节。它是服务API的一部分(服务和服务使用者之间的“合同”)

    控制器需要一个承诺来解决数据问题,并根据自己的意愿进行处理。
    承诺是如何构建的,数据是如何获取的,等等,这些都是实现细节。
    您可以随时将该服务与执行完全不同的操作的服务交换,只要它履行了合同(即返回一个承诺,该承诺与准备好的数据一致)


    也就是说,如果您仅在视图中使用数据(即,在获取数据后不直接在控制器中对其进行操作),情况似乎是这样的,那么您可以使用
    ngResources
    方法:

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

    $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()
    。您可以使用承诺链接:

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

    当您使用
    ngRoute
    时,我建议您在路由配置中解析数据,并在解析完所有数据后加载视图

    $routeProvider
      .when('/your-url', {
        templateUrl: 'path/to/your/template.html',
        controller: 'YourCtrl',
    
        // that's the point !
        resolve: {
          superAwesomeData: function (DataService) {
            return DataService.getData();
          }
        }
      });
    
    angular.module('youModule')
      .controller('YourCtrl', function (superAwesomeData) {
    
        // superAwesomeData === [...];
    
      });
    
    现在,可以将
    superwesomedata
    注入控制器,它将包含已解析的数据

    $routeProvider
      .when('/your-url', {
        templateUrl: 'path/to/your/template.html',
        controller: 'YourCtrl',
    
        // that's the point !
        resolve: {
          superAwesomeData: function (DataService) {
            return DataService.getData();
          }
        }
      });
    
    angular.module('youModule')
      .controller('YourCtrl', function (superAwesomeData) {
    
        // superAwesomeData === [...];
    
      });
    

    您是否在项目中使用了
    ngRoute
    ?我认为您拥有的是一个非常好的解决方案。您不必等待承诺得到解决,它违背了异步javascript的目的。问问自己,为什么要让它同步运行?将我的评论移至answer@meriadec:是的,我正在使用ngRoute。。。但你为什么要问?事实上,我想在控制器代码中等待数据,而不是在HTML模板中。无论如何,谢谢你的提示。另外,在控制器中,我当然希望避免阻塞和等待,我想知道是否会有一种模式以某种方式进行非阻塞等待…@andimeter:LOL.non-blocking wait(也称为promise:P)@andimeter是的,不幸的是没有等待只是承诺或回调方法。有趣。当我了解ngRoute时,我有点忽略了属性“resolve”。所以,我现在又学到了一些东西;)无论如何,AFAIU,您的建议会阻止控制器的实例化,直到所有问题都得到解决。相反,在我的例子中,我有一个实例化的控制器,并且希望在一个处理程序方法中暂停语句流,而不是延迟控制器实例化。如果我可以接受2个答案,我也会接受这个。我将绿色复选标记授予按时间顺序排列的第一个答案。但我不得不说,在专家系统的回答中有一些非常有用的提示。我求助于向上投票。。。