Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angularjs deferred promise not deferring

struggling to get promises working correctly in angularjs service provider i've read the docs as well as numerous examples (here, here and here) and i think i've got my syntax ok (although obviously something is wrong)

app module and controller look like

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

myApp.controller('Controller_1', ['$scope', 'Service_1', function($scope, Service_1) {

    var myName = "Ben";

    Service_1.slowService(myName)
        .then(Service_1.fastService(name));

    $scope.myName = myName;
}]);

the service (with the slow function) looks like this:

myApp.service('Service_1', function($q) {
    this.slowService = function (name) {
        var deferred = $q.defer();
        console.log('Start of slowService:', name, Date.now());

        setTimeout(function() {
            console.log('setTimeout name:', name, Date.now());

            if(name){
                name = 'Hello, ' + name + " is learning Angularjs";
                alert(name); 
                    console.log('name:', name);
                deferred.resolve(name);
            } else {
                deferred.reject('No name supplied !');
            }
        }, 3000);

        return deferred.promise;
    };

    this.fastService = function(name){ 
        console.log('Start of fastFunction:', name, Date.now());
        alert('Hello ' + name + ' - you are quick!'); 
    }; 
});

console output looks like this:

Start of slowService: Ben 1420832940118
Start of fastFunction: result 1420832940122
setTimeout name: Ben 1420832948422
name: Hello, Ben is learning Angularjs

The fastService is starting before the slowService completes, despite using a deferred object / promise in Service_1 and a .then in the controller...

Can anyone point out what's wrong with the code ?

jsfiddle is here

EDIT: put the fast function in the service so there's no confusion with hoisting etc - still the same result - js fiddle updated

like image 762
goredwards Avatar asked Feb 23 '26 19:02

goredwards


2 Answers

The fastService is starting before the slowService completes

That is because you are executing the function fastService before slowService async callback runs.Instead you would want to provide the reference of the function. i.e .then(Service_1.fastService(name)); should be .then(Service_1.fastService); or .then(function(name){ Service_1.fastService(name); }); otherwise fastservice will just run right away, before the async part of the slowService runs.

Use $timeout with that the advantage is that it already returns a promise so you do not need to create a deferred object and resulting in deferred anti-pattern.

myApp.service('Service_1', function($q, $timeout) { //<-- Inject timeout
    this.slowService = function (name) {
        console.log('Start of slowService:', name, Date.now());

        return $timeout(function() {
            console.log('setTimeout name:', name, Date.now());

            if(name){
                name = 'Hello, ' + name + " is learning Angularjs";
                return name; //return data
           }
           //Reject the promise
           return $q.reject('No name supplied !');

        }, 3000);


    };
   //...
});

and when consuming just chain through:

  Service_1.slowService(myName)
     .then(Service_1.fastService);

So instead of timeout even if you are using $http in your original method just return the promise from http rather than creating a deferred object. Also just keep in mind when you use the syntax .then(Service_1.fastService); and if you are referring to this context in the fast service it wont be the service instance.

like image 159
PSL Avatar answered Feb 25 '26 08:02

PSL


The way you are passing your function to then() part is not correct. Pass it like this :

Service_1.slowService(myName)
         .then(function(){fastFunction(name)});
like image 27
YAAK Avatar answered Feb 25 '26 08:02

YAAK