# Logging out using nested promises

Is it OK to do that ?

for example, I have my log out service

logout: function() {
var defer = $q.defer(); this.getCustomer().then(function(credentials) {$http.post(CONSTANT_VARS.BACKEND_URL + '/auth/logout',
).success(function(data) {
if (data.error) {
defer.reject(data);
}
LocalForageFactory.remove(CONSTANT_VARS.LOCALFORAGE_CUSTOMER).then(function() {
/*Removing LocalForage Items*/
cleanLocalForage();
defer.resolve(data);
}, function(err) {
console.log(err);
defer.reject(data);
});
}).error(function(data) {
cleanLocalForage();
defer.reject(data);
});
}, function(err) {
defer.reject(err);
});
return defer.promise;
},

and then I have a function in a controller which returns an error once the session expires. When the session expires I need to logout the user and redirect him to the login path. So, this is what I have so far:

$scope.removeSlip = function(slip) { BetSlipFactory.removeSlip(slip).then(function() { }, function(err) { console.log(err); AuthFactory.logout();$location.path('/');
});
};

or should I do something like this with the logout promise into the BetSlipFactory.removeSlip() promise ?

$scope.removeSlip = function(slip) { BetSlipFactory.removeSlip(slip).then(function() { }, function(err) { console.log(err); AuthFactory.logout().then(function() {$location.path('/');
})
});
};

there is my question: what is the proper way in this case ?

• The first version sets the path to '/' immediately after calling logout while the second version waits for the logout to complete before redirecting. Since I don't know how the logout works I can't tell you if it's necessary to wait for it to complete. But I can see that you are not using promises consequently. It's not necessary to have that many error handlers. – SpiderPig May 6 '15 at 23:53

Well, Promises are designed so that you won't have to nest at all! You can think of Promises as try-catch-finally statements. And the nice thing about Promises is that if you return a promise inside then, the next chained then waits for that promise instead of the original. Here's a simplified version of your code (assuming I understood it correctly).

// Call the async function #1
return this.getCustomer().then(
function(credentials) {
// Success for async function #1

// You can return promises. It will be listened to in the next .then()
return $http.post(CONSTANT_VARS.BACKEND_URL + '/auth/logout', { username: credentials.username, customer: credentials.customer }); } ).then( function(data) { // Success callback for async function #2 (the POST request) // We can also return a newly rejected promise to fail the next then // Or send back the promise of your remove operation //$.Deferred().reject().promise(), Deferred is read-write, Promise is read-only
return data.error ? new Promise.reject() : LocalForageFactory.remove(CONSTANT_VARS.LOCALFORAGE_CUSTOMER);

},
function(error) {
// Fail callback for async function #2 (the POST request)

cleanLocalForage();
}
).then(
function() {
// Success callback for async function #3 (the remove)

cleanLocalForage();
},
function(err) {
// Fail callback for async function #3 (the remove)

console.log(err);
}
);

The return value is either a resolved or rejected promise, depending on the result of the entire chain. If the entire thing resolves, the return is a resolved promise. If it rejects, then it returns a rejected promise. You can also recover from a reject by returning a promise. If that promise resolves, the next chain resolves and so on.

It's the main reason why it's called "then". It's like "Do this, then what?". The idea of the promise is to be some sort of linear flow-control mechanism, to avoid nested callbacks and proxy deferreds.

As for the other function, assuming logout is an async operation, you can do it like:

BetSlipFactory.removeSlip(slip).then(null, function(err) {
console.log(err);
return AuthFactory.logout();
}).then(function() {
\$location.path('/');
});