dork dork - 6 months ago 13
Javascript Question

deferred promise value not updating/resolving/deferring

I have a controller function that creates something. When the function is called, a

setInterval
run to get the status of the item.

Here is the service:

(function () {
'use strict';

function myService($q) {
let deferred = $q.defer();

function createSomething(name) {
Meteor.call('createSomething', name, (err, res) {
if (err) {
deferred.reject(err);
} else {
//value returned is the created item (id, name, status)
deferred.resolve(res);
}
});

return deferred.promise;
}

function getStatus(id) {
Meteor.call('getStatus', id, (err, res) {
if (err) {
deferred.reject(err);
} else {
//statuses are queued, processing, created
deferred.resolve(res);
}
});

return deferred.promise;
}

return {
createSomething: createSomething,
getStatus: getStatus
}
}

angular.module('myApp').factory('myService', myService);
})();


And here is the controller:

(function () {
'use strict';

function myController($scope, myService) {
let ctrl = this;

ctrl.create = (name) => {
myService.createSomething(name)
.then((item) => {
ctrl.statusInterval = setInterval(() => {
myService.getStatus(item.data.id)
.then((status) => {
//status is always 'queued' :(
if (status.data.status === 'created') {
clearInterval(ctrl.statusInterval);
//do something
}
});
}, 5000);
});
};
}

angular.module('myApp').controller('myController', myController);
})();


When I check the value of the
response
in
getStatus
of the service, the status changes every time it is called (queue -> processing ... processing -> created). However, the value of
status
in the controller is always
queue
.

How do I get the promise value to resolve?

Answer

createSomething() and getStatus() need to create and return their own promise. They can't share a promise and work properly in all cases.

In addition, they should create and return a unique promise each time they are called, not the same promise every time they are called. Remember, promises are one-way state machines. Once resolved or rejected, their state never changes, even if resolve() or reject() is called again on them.

Here's an example:

    function createSomething(name) {
        // create a unique deferred inside this function each time you call it
        let deferred = $q.defer();
        Meteor.call('createSomething', name, (err, res) {
            if (err) {
                deferred.reject(err);
            } else {
                //value returned is the created item (id, name, status)
                deferred.resolve(res);
            }
        });

        return deferred.promise;
    }