Question
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()
Answer
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 :)