Javascript AngularJS $http 在服务中调用,返回解析的数据,而不是承诺

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27238928/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 23:54:15  来源:igfitidea点击:

AngularJS $http call in a Service, return resolved data, not promises

javascriptangularjsangular-promise

提问by iQ.

I want to know if it is possible to make a service call that uses $httpso it returns data directly without returning a promise? I have tried to use the $qand defer without any luck.

我想知道是否可以进行使用的服务调用,$http以便它直接返回数据而不返回承诺?我曾尝试使用$qand defer 没有任何运气。

Here is what I mean:

这就是我的意思:

I have a service:

我有一个服务:

angular.module('myModule').factor('myService', ['$http', '$q',
    function($http, $q) {

        // Public API
        return {
            myServiceCall: function() {
                return $http.get('/server/call');
            }
        };
    }
]);

And this is how I would call it:

这就是我的称呼:

// My controller:
myService.myServiceCall().then(function(data) {
  $scope.data = data;
});

I want to avoid that and instead wish to have:

我想避免这种情况,而是希望:

$scope.data = myService.myServiceCall();

I want it to be fully resolved at that line, is it possible?

我希望它在那条线上得到完全解决,这可能吗?

I have tried some combinations of $q, defer and 'then' methods but can't seem to get it right since the method returns immediately.

我尝试了 $q、defer 和 'then' 方法的一些组合,但似乎无法正确组合,因为该方法立即返回。

Edit:

编辑:

If you are wondering why, the main reason is that I wanted to simplify the controller code, this is easily done with ngResource as those calls are automatically resolved in templates, so I wanted to avoid the need to do the the whole '.then' everytime.

如果你想知道为什么,主要原因是我想简化控制器代码,这很容易用 ngResource 完成,因为这些调用在模板中自动解析,所以我想避免需要做整个 '.then'每次。

It's not that I don't like the Async nature, most of our code leverages it, it's just in somecases, having a synchronous way is helpful.

并不是我不喜欢 Async 性质,我们的大部分代码都利用了它,只是在某些情况下,使用同步方式是有帮助的。

I think for now as some of you have pointed out, I will use the $resource for a near enough solution.

我认为现在正如你们中的一些人指出的那样,我将使用 $resource 来获得足够接近的解决方案。

回答by GregL

There are two ways I can think of to do this. The first is definitely better than the second.

我可以想到两种方法来做到这一点。第一个肯定比第二个好。

The first way: using the resolveproperty of routes

第一种方式:利用resolve路由的属性

You can use the resolveproperty of the route configuration object to specify that a promise must be resolved and the resolved value be used for the value of one of your controller dependencies, so that as soon as your controller runs, the value is immediately available.

您可以使用resolve路由配置对象的属性来指定必须解析承诺并将解析的值用于您的控制器依赖项之一的值,以便您的控制器一运行,该值立即可用。

For example, say you have the following service:

例如,假设您有以下服务:

app.service('things', ['$http', '$q', function ($http, $q) {
    var deferred = $q.defer();

    $http({
        method: 'GET',
        url: '/things',
        cache: true
    }).success(function (data) {
        deferred.resolve(data);
    }).error(function (msg) {
        deferred.reject(msg);
    });

    return deferred.promise;
}]);

Then you could define your route something like this:

然后你可以像这样定义你的路线:

$routeProvider.when('/things', {
    controller: ['$scope', 'thingsData', function ($scope, thingsData) {
        $scope.allThings = thingsData;
    }],
    resolve: {
        thingsData: ['things', function (things) {
            return things;
        }]
    }
});

The key in the resolveobject corresponds to the name of the second dependency for the controller, so even though it returns a promise, that promise will be resolved before the controller is run.

resolve对象中的键对应于控制器的第二个依赖项的名称,因此即使它返回一个承诺,该承诺也会在控制器运行之前被解析。

The second way: Make the request well before you need the data

第二种方式:在需要数据之前做好请求

The second way, which is not at all ideal, and will likely bite you on the bum at some point, is to make the request for the data early on, such as when your app is initialised, and then actually get the data later on, say on a page that requires 3 clicks to get to from the home page. Fingers crossed, if the stars have aligned, your http request will have returned by then and you will have the data to use.

第二种方式一点也不理想,并且可能在某些时候会让您感到不舒服,它是在早期(例如在您的应用程序初始化时)发出对数据的请求,然后在稍后实际获取数据,比如说在需要点击 3 次才能从主页访问的页面上。手指交叉,如果星星已经对齐,那么您的 http 请求将在那时返回,您将拥有可以使用的数据。

angular.module('myModule').factory('myService', ['$http', '$q', function($http, $q) {
    var data = [];

    function fetch() {
        $http.get('/server/call').then(function (d) { data = d; });
    }

    // Public API
    return {
        fetchData: fetch,
        myServiceCall: function () {
            return data;
        }
    };
}]);

Then, in your module's run function, make the request:

然后,在您的模块的 run 函数中,发出请求:

angular.module('myModule').run(['myService', function (myService) {
    myService.fetchData();
});

Then, in a controller for a page that is guaranteed to run at least 3 seconds after the app starts, you could do as you suggested:

然后,在保证在应用程序启动后至少运行 3 秒的页面的控制器中,您可以按照您的建议进行操作:

 angular.module('myModule').controller('deepPageCtrl', ['$scope', 'myService', function ($scope, myService) {
      $scope.data = myService.myServiceCall();
      if (angular.isArray($scope.data) && $scope.data.length === 0) {
           panic("data isn't loaded yet");
      }
  }]);

Bonus, equally bad third way: Synchronous AJAX request

奖励,同样糟糕的第三种方式:同步 AJAX 请求

Do as ricick suggests, and use the synchronous AJAX request possible with jQuery's .ajax()method.

按照 ricick 的建议去做,并使用 jQuery.ajax()方法可能的同步 AJAX 请求。

回答by ricick

This is not possible, as http calls are inherently asynchronous. That is, you need to wait for the server to respond.

这是不可能的,因为 http 调用本质上是异步的。也就是说,您需要等待服务器响应。

The $resource service kind of gets around this by returning a proxy object that is populated with the returned data on server response, but it's still not fully resolved in one line.

$resource 服务通过返回一个代理对象来解决这个问题,该对象由服务器响应中返回的数据填充,但它仍然没有在一行中完全解决。

Edit:

编辑:

It is actually possible to make synchronous http requests with the jquery ajax method, by setting the "async" option to false.

通过将“async”选项设置为false,实际上可以使用jquery ajax 方法进行同步http 请求。

You could create a service that wraps this, however your application will "lock up" while the request waits for a server response, so for most cases this would be bad practice. There are also other restrictions on this type of request.

您可以创建一个包装它的服务,但是您的应用程序将在请求等待服务器响应时“锁定”,因此在大多数情况下,这将是不好的做法。此类请求还有其他限制。

See the docs for more detail:

有关更多详细信息,请参阅文档:

http://api.jquery.com/jQuery.ajax/

http://api.jquery.com/jQuery.ajax/

回答by Boris Charpentier

Long time ago (in angular land, actually sometime last year) it was actually how it works.

很久以前(在有角的土地上,实际上是去年的某个时候)它实际上是如何工作的。

But now it's no more the case, I think it's due to behavior differences of promise in view and controller, more here about the deprecation : Angularjs promise not binding to template in 1.2

但现在情况不再如此,我认为这是由于视图和控制器中承诺的行为差异,更多关于弃用的信息: Angularjs promise not binding to template in 1.2