AngularJS deferred.reject not working but $q.reject working - javascript

I am confused between Angular JS deferred and $q. I found this SO Question that explains the difference between $q.defer() and $q.It explains
$q.reject is a shortcut to create a deferred and then reject it immediately
So $q.reject() must be equal to
var deferred = $q.defer(); deferred.reject(), if not please explain the actual difference between the two.
But in my case, $q.reject() is working, but deffered.reject() is not working. Also we need to return rejected promised like $q.reject() but not deferred.reject(). I have seen examples where there is no return on deffered.reject()
This is the code
var deferred = $q.defer();
myService.getData()
.then(function(response){
deferred.notify('Just a notification');
deferred.reject('rejected');
})
.then(function(response) {
console.log('done');
}, function(response) {
console.log('rejected');
})
This is not working, but when I replaced deferred.reject with $q.reject(), the promise has been rejected and the control is moved to the error function of the followed then block.
Any help is greatly appreciated. Thanks in advance.

It doesn't work when you use deferred.reject because you are not returning new rejected promise. You can use both $q.reject() and deferred.reject() you just need to return a promise in both cases.
You need to to understand that
$q.reject() is rejected promise object
deferred.reject() is not a promise, but deferred object which has rejected promise in one of its properties (namely, $promise).
So you can return any object or value and it will become a new promise object and will be passed to the next then block in chain. However, when you return deferred.reject() it will be passed as just some object (one more time, it is not a promise, but it has a promise inside) and next promise will get resolved successfully of course.
It will work properly with deferred too if you return corresponding promise:
var deferred = $q.defer();
myService.getData()
.then(function(response) {
deferred.notify('Just a notification');
deferred.reject('rejected');
return deferred.promise;
//return $q.reject();
})
.then(function(response) {
console.log('done');
}, function(response) {
console.log('rejected');
});
And finally answer to you question: $q.reject() is a promise object with status "rejected". deferred.reject() is not a promise, but it has rejected promise object inside as deferred.$promise. What to use? You should use $q.reject(), using dummy deferred object is redundant in this case and considered bad practice, in fact it even has a name as deferred anti-pattern.

Make sure you are returning a promise.
function getData() {
var deferred = $q.defer();
myService.getData()
.then(function (response) {
deferred.resolve('Just received a notification');
}).catch(function (err) {
deferred.reject(err);
};
return deferred.promise;
}
getData().then(function (response) {
console.log('done');
}, function (response) {
console.log('rejected');
});

This is working with Q (https://github.com/kriskowal/q)
var def = Q.defer();
def.promise
.then(
function(ok){
return ok;
},
function(err){
var d = Q.defer();
d.reject(err);
return d.promise;
}
)
.then(
function(ok){
console.log('ok',ok);
},
function(err){
console.log('err',err);
}
);
def.reject('error');

Related

javascript not resolving promise

Javascript code, trying to resolve a promise immediately:
var promiseData;
var promise = <<<promise maker>>>.then(function (myContent) {
console.log("success");
}, function () {
console.log("fail!");
});
Promise.resolve(promise)
console.log("about to return");
return promiseData;
which output's to the console:
about to return
success
I have a requirement to make the promise return immediately (the promise is being created in a callback method, and the method needs to return a value immediately, returning the data later means we are no longer in the correct context and the value (that has not yet been returned) has already been used (as undefined).
Any suggestions of what I might be doing wrong?
Update:
<<<promise maker>>> is a call to a dependency that returns a promise;
It looks like you expect Promise.resolve(promise) to immediately halt, wait until the promise is resolved, and continue afterwards. That would come close to synchronous execution.
However, Promise.resolve(value) returns a Promise that immediately resolves with value, it does not resolve an existing Promise.
What you're looking for is await (or just Promise.then):
var promise = <<<promise maker>>>.then(function (myContent) {
console.log("success");
}, function () {
console.log("fail!");
});
promise.then(function() {
console.log("about to return");
});
You might observe that I left out the promiseData in the snippet. That's because in order to return the data at the right moment, you have to be asynchronous there as well. So you have to actually return a Promise that will resolve with promiseData, it comes down to:
<<<promise maker>>>
.then(function(promiseData) {
console.log('success');
return promiseData;
})
.then(function(promiseData) {
console.log('about to return');
return promiseData;
})
.catch(function(err) { console.log('fail!'); })
If I am not wrong, this function flow is near what you need, but it also returns a promise resolved into promiseData:
async function getPromiseData() {
try {
const promiseData = await <<<promise maker>>>;
console.log("success");
console.log("about to return");
return promiseData;
} catch (err) {
console.log("fail!");
}
}

Angular 1.6.4 $http post callback not called [duplicate]

I'm finding it hard to understand the "deferred antipattern". I think I understand it in principal but I haven't seen a super simple example of what a service, with a differed promise and one with antipattern, so I figured I'd try and make my own but seeing as how I'm not super in the know about it I'd get some clarification first.
I have the below in a factory (SomeFactory):
//url = 'data.json';
return {
getData: function(){
var deferred = $q.defer();
$http.get(destinationFactory.url)
.then(function (response) {
if (typeof response.data === 'object') {
deferred.resolve(response.data);
} else {
return deferred.reject(response.data);
}
})
.catch(function (error) {
deferred.reject(error);
});
return deferred.promise;
}
The reason I am checking its an object is just to add a simple layer of validation onto the $http.get()
And below, in my directive:
this.var = SomeFactory.getData()
.then(function(response) {
//some variable = response;
})
.catch(function(response) {
//Do error handling here
});
Now to my uderstanding, this is an antipattern. Because the original deferred promise catches the error and simply swallows it. It doesn't return the error so when this "getData" method is called I have do another catch to grab the error.
If this is NOT an antipattern, then can someone explain why both require a "callback" of sorts? When I first started writing this factory/directive I anticipated having to do a deffered promise somewhere, but I didn't anticipate having to .catch() on both sides (aka I was sort of thinking I could get the factory to return the response or the error if I did a SomeFactory.getData()
Is this a “Deferred Antipattern”?
Yes, it is. 'Deferred anti-pattern' happens when a new redundant deferred object is created to be resolved from inside a promise chain. In your case you are using $q to return a promise for something that implicitly returns a promise. You already have a Promise object($http service itself returns a promise), so you just need to return it!
Here's the super simple example of what a service, with a deferred promise and one with antipattern look like,
This is anti-pattern
app.factory("SomeFactory",['$http','$q']){
return {
getData: function(){
var deferred = $q.defer();
$http.get(destinationFactory.url)
.then(function (response) {
deferred.resolve(response.data);
})
.catch(function (error) {
deferred.reject(error);
});
return deferred.promise;
}
}
}])
This is what you should do
app.factory("SomeFactory",['$http']){
return {
getData: function(){
//$http itself returns a promise
return $http.get(destinationFactory.url);
}
}
while both of them are consumed in the same way.
this.var = SomeFactory.getData()
.then(function(response) {
//some variable = response;
},function(response) {
//Do error handling here
});
There's nothing wrong with either examples(atleast syntactically)..but first one is redundant..and not needed!
Hope it helps :)
I would say that it is the classic deferred anti-pattern because you are creating needless deferred objects. However, you are adding some value to the chain (with your validation). Typically, IMO, the anti-pattern is particularly bad when deferred objects are created for very little or no benefit.
So, the code could be much simpler.
$q promises have a little documented feature of automatically wrapping anything returned inside a promise in a promise (using $q.when). In most cases this means that you shouldn't have to manually create a deferred:
var deferred = $q.defer();
However, that is how the documentation demonstrates how to use promises with $q.
So, you can change your code to this:
return {
getData: function(){
return $http.get(destinationFactory.url)
.then(function (response) {
if (typeof response.data === 'object') {
return response.data;
} else {
throw new Error('Error message here');
}
});
// no need to catch and just re-throw
});
}
Using the $q constructor is a deferred anti-pattern
ANTI-PATTERN
vm.download = function() {
var url = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf";
return $q(function(resolve, reject) {
var req = {
method: 'POST',
url: url,
responseType: 'arraybuffer'
};
$http(req).then(function(response) {
resolve(response.data);
}, function(error) {
reject(error);
});
});
}
CORRECT
vm.download = function() {
var url = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf";
var req = {
method: 'POST',
url: url,
responseType: 'arraybuffer'
};
return $http(req).then(function(response) {
return response.data;
});
}
The $http service already returns a promise. Using the $q constructor is unnecessary and error prone.

Asynchronus calls in angularjs

I am new to Javascript and Angularjs. I wanted to know , how to call a function asynchronously without waiting for it to return from it.
Please let me know and if there is some example then it would be very helpful.
Regards,
nG
Use Angular's deferred:
function myAsyncFunction() {
var deferred = $q.defer();
//..
setTimeout(function() {
deferred.resolve({ message: "resolved!" });
// or deferred.reject({ message: "something went terribly wrong!!" });
}, 1000);
//..
return deferred.promise;
}
myAsyncFunction()
.then(function(data){
// success
console.log("success", data.message);
}, function(data) {
// fail
console.log("error", data.message);
}).finally(function() {
// always
});
You can use a deferred to return a promise, you can then resolve the promise once your function is complete. Try something like this:
http://jsfiddle.net/adcoxwga/
var myApp = angular.module('myApp',[])
.service('myService', function($q, $timeout){
this.someFunction = function(){
var deferred = $q.defer(); //making a new deferred
$timeout(function(){
deferred.resolve('something'); //resolving the deferred with a response
}, 3000);
return deferred.promise; //returning a promise
}
})
.controller('MyCtrl', function($scope, myService){
myService.someFunction().then(function(response){ //calling the asynchronous function
console.log(response); //getting response
}, function(error){
console.log(error); //getting error
});
});
You have a couple of different options ahead of you, but one thing to note is that you have to use a callback or promise for asynchronous activity. Since you are using angular, I'd suggest using promise's.
Using a promise
If you are writing an http call to an api, you can use either $http or $resource. If you start to research angular providers, you will see that $http returns a promise, while $resource returns a promise but you must call it specifically to access it. For instance:
someService
function someServiceFunction () {
return $http.get('some/url');
}
someController
$scope.results = [];
someService.someServiceFunction().then(function(data) {
$scope.results = data;
});
Something to note is that the first returned function is the success scenario and if you declare a second callback, then it is the failure scenario.
If you were to use callbacks in the same scenario:
Using a callback
someService
function someServiceFunction (callback) {
return $http.get('some/url')
.success(callback);
}
someController
$scope.results = [];
someService.someServiceFunction(function(data, status, headers, config) {
$scope.results = data;
});
Here's a link to the $http provider.
Here's a link to the $resource provider.
Cheers!

Chaining Angular promise rejections

I have a chained promise and in the case of a rejection for either of the promises, I need to perform an async operation (get the translated error message). As I've already got a chained promise on success, I assume it's not possible to also chain on rejection - I am attempting to simply nest the async calls, but I'm not getting the resolved promise back from deferred.reject(deferredRejection.promise); below. Pointers appreciated!
login: function(email, password) {
var deferred = $q.defer();
AuthService.login(email, password).then(function(response) {
var user = {
'accountToken': response.accountToken,
'email': response.username,
'onboarded': response.onboarded,
'verified': response.verified
};
return SyncStorageService.write(SyncStorageService.storageKeys.user,
user);
}, function(error) {
// login failed
var deferredRejection = $q.defer();
$translate('ALERTS.LOGIN_FAILED').then(function(translatedValue) {
deferredRejection.resolve(translatedValue);
});
deferred.reject(deferredRejection.promise);
}).then(function(data) {
deferred.resolve(data);
}, function(error) {
// saving data failed
var deferredRejection = $q.defer();
$translate('ALERTS.UNKNOWN').then(function(translatedValue) {
deferredRejection.resolve(translatedValue);
});
deferred.reject(deferredRejection.promise);
});
return deferred.promise;
}
Updated Solution:
Based on the answer below, I was able to re-write the code as follows:
login: function(email, password) {
return AuthService.login(email, password).then(function(response) {
return {
'accountToken': response.accountToken,
'email': response.username,
'onboarded': response.onboarded,
'verified': response.verified
};
}).then(function(data) {
return SyncStorageService.write(SyncStorageService.storageKeys.user,
data);
});
}
Notes:
Both AuthService.login and SyncStorageService.write now reject promises with an Error object (e.g. new Error('ALERT.ERROR_MESSAGE');), which bubbles up through login to the controller (previously was doing the translation at the service level);
The controller that calls the login method has .then() and .catch() blocks - on a .catch(), the passed Error.message is translated and displayed.
It looks like you're not really chaining promises, and using the forgotten promise/deferred anti pattern. Making a few assumptions about how you actually want it to behave, and factoring out the calls to $translate, then something like the following I suspect is what you're after:
login: function(email, password) {
return AuthService.login(email, password).then(function(response) {
return {
'accountToken': response.accountToken,
'email': response.username,
'onboarded': response.onboarded,
'verified': response.verified
};
}, function() {
return $q.reject('ALERTS.LOGIN_FAILED');
}).then(function(user) {
return SyncStorageService.write(SyncStorageService.storageKeys.user, user).catch(function() {
return $q.reject('ALERTS.UNKNOWN');
});
}).catch(function(message) {
return $translate(message).then(function(translatedValue) {
return $q.reject(translatedValue);
});
});
}
The main things to keep in mind are:
If you definitely want to reject the derived promise, return $q.reject(error) from the success or error callback.
All the error callbacks above do this. The ones after attempted login or saving use the translation key as the error that will be eventually passed to the final catch callback. The success callback from $translate also does this to transform its resolved promise to a rejected one, so the final catch callback returns a rejected promise, so the calling code gets a rejected promise, and (presumably) shows the translated error to the user.
If you definitely want to resolve the derived promise, return anything that isn't a promise from he success or error callbacks. The derived promise will be resolved with that value. (This includes undefined if you don't have an explicit return value).
This is what is done above when returning the user return {'accountToken'.... in the first callback.
If you want to defer the resolution/rejection of a promise, return another promise from the success or error callback. Then the derived promise will be eventually resolved or rejected in whatever manner this other promise is resolved/rejected.
This is what's done above when returning SyncStorageService.write..., and when returning $translate(....

Angularjs promise rejection chaining

I need to create chained promises:
var deferred = $q.defer();
$timeout(function() {
deferred.reject({result: 'errror'});
}, 3000);
deferred.promise.then(angular.noop, function errorHandler(result) {
//some actions
return result;
}).then(function successCallback(result) {
console.log('what do I do here?');
return result;
}, function errorCallback(result) {
$scope.result= result;
return result;
});
If I put an errorCallback into the first then, the second then will be resolved and its successCallback will be called . But if I remove errorHandler then second promise will be rejected.
According to Angular JS docs the only way to propagate rejection is to return $q.reject(); and it looks not obvious, especially because I have to inject $q service even if it is not needed;
It can also be done by throwing an exception in errorHandler, but it writes exception trace to console, it is not good.
Is there another option to do this in a clear way? And what is the reason? Why it is done? In which case, the current behavior can be useful?
And what the reason why it is done. In which case, the current behavior can be useful?
It can be useful when in errorHandler you could try to repair error state and resolve promise somehow.
var retriesCount = 0;
function doWork()
{
return $http.post('url')
.then(function(response){
// check success-property of returned data
if(response.data.success)
// just unwrap data from response, may be do some other manipulations
return response.data;
else
// reject with error
return $q.reject('some error occured');
})
.catch(function(reason){
if(retriesCount++ < 3)
// some error, let me try to recover myself once again
return doWork();
else
// mission failed... finally reject
return $q.reject(reason);
});
}
doWork().then(console.log, console.error);
Late to the party, but as I am here;
I prefer to use the $http error for its native error handling, rather than returning a success via a 200 and an error status in the response.
printing 400 or 500 errors in the console is not an issue, if you are debugging you see them if not you don't.
angular.module('workModule', [])
// work provider handles all api calls to get work
.service('workProvider', ['$http', '$q', function($http, $q) {
var endpoint = '/api/v1/work/';
this.Get = function(){
// return the promise, and use 404, 500, etc for errors on the server
return $http.get(endpoint);
};
}])
.controller('workController', ['workProvider', function('workProvider'){
workProvider.Get().then(
function(response){ // success
console.log(response.data);
},
function(response){ // error
console.log(response.data);
}
)
}])

Categories

Resources