最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - AngularJs $q.defer() not working - Stack Overflow

programmeradmin4浏览0评论

I had some problems with $q.defer();
When I used callbacks instead, my code was working(the view was updated), but with $q.defer(); it's not.

This is my code:
The service:

eventsApp.factory('eventData', function($http, $q) {
    return {
        getEvent: function(callback) {
            var deferred = $q.defer();
            $http({method: 'GET', url: '/node/nodejsserver/server.js'}).
                success(function(data, status, headers, config){
                    //callback(data.event);
                    deferred.resolve(data.event);
                    console.log('status: ', status, ' data: ', data);
                }).
                error(function(data, status, headers, config){
                    deferred.reject(status);
                    console.log('status: ', status);
                });
            return deferred.promise;
        }
    };
});

The controller:

eventsApp.controller('EventController', 
    function EventController($scope, eventData) {
        $scope.event = eventData.getEvent();
    }
);

But it doesn't work.

Then I found this answer and I updated my controller like this:

eventsApp.controller('EventController', 
    function EventController($scope, eventData) {
        eventData.getEvent().then(function(result) {
           $scope.event = result;
        });
    }
);

and it works.
What is the difference between the nonworking and the working code?

I had some problems with $q.defer();
When I used callbacks instead, my code was working(the view was updated), but with $q.defer(); it's not.

This is my code:
The service:

eventsApp.factory('eventData', function($http, $q) {
    return {
        getEvent: function(callback) {
            var deferred = $q.defer();
            $http({method: 'GET', url: '/node/nodejsserver/server.js'}).
                success(function(data, status, headers, config){
                    //callback(data.event);
                    deferred.resolve(data.event);
                    console.log('status: ', status, ' data: ', data);
                }).
                error(function(data, status, headers, config){
                    deferred.reject(status);
                    console.log('status: ', status);
                });
            return deferred.promise;
        }
    };
});

The controller:

eventsApp.controller('EventController', 
    function EventController($scope, eventData) {
        $scope.event = eventData.getEvent();
    }
);

But it doesn't work.

Then I found this answer and I updated my controller like this:

eventsApp.controller('EventController', 
    function EventController($scope, eventData) {
        eventData.getEvent().then(function(result) {
           $scope.event = result;
        });
    }
);

and it works.
What is the difference between the nonworking and the working code?

Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Aug 23, 2014 at 15:18 trajcetrajce 1,4903 gold badges23 silver badges38 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 11

The non working code uses automatic promise unwrapping which was deprecated and removed in recent versions of Angular. It was deemed too magical.

Angular used to do the following when you returned a promise:

  • Return an empty array.
  • Populate it later on when the request arrives.
  • Trigger a digest on its own.

This behavior was deemed confusing and magical by Angular developers and was deprecated (in 1.2), deactivated and soon (1.3) removed in Angular. The correct way to assign a value through a promise is like you've indicated in the second example:

eventData.getEvent().then(function(result) {
    $scope.event = result;
});

From the Angular 1.3 (pending) release docs:

$parse: due to fa6e411d, promise unwrapping has been removed. It has been deprecated since 1.2.0-rc.3. It can no longer be turned on. Two methods have been removed:

And from the 1.2 release docs:

$parse and templates in general will no longer automatically unwrap promises.

Before:

$scope.foo = $http({method: 'GET', url: '/someUrl'}); <p>{{foo}}</p>

After:

$http({method: 'GET', url: '/someUrl'})

.success(function(data) { $scope.foo = data; });``

{{foo}}

`

This feature has been deprecated. If absolutely needed, it can be reenabled for now via the $parseProvider.unwrapPromises(true) API.

While we're here avoid the deferred anti pattern, $http already returns the promise so you can simply return it rather than using $q.defer.

Edit: check Benjamin's answer

In your service, you are returning a promise object, promise object has .then method.

you are assigning the promise object to $scope.event, so you wont get the data (in the latest version according to Benjamin)

when you resolve the promise using deferred.resolve(data.event) then the function you passed as argument to .then method will be called with this resolved data.

You can give a second argument to the .then, which will be called when you do deferred.reject()

This is basic functionality of promise api. Just read the docs for more info https://docs.angularjs/api/ng/service/$q

发布评论

评论列表(0)

  1. 暂无评论