Rejecting Angular $http promise - javascript

I need to reject an $http promise call in the success/then function. I can see 2 options: 1) thrown an error - this garbages up the console and 2) use separate defer call and reject that. Is there a cleaner/more concise way? I have a feeling I am overlooking something obvious.
Error:
return $http.get(url}.then(function(r) {
throw new Error('Booh');
});
With $q:
var deferred = $q.defer();
$http.get(url}.then(function(r) {
deferred.reject("Booh");
});
return deferred.promise;

Try this:
function myfunction()
{
return $http.post('url')
.then(function(response){
// check success-property of returned data
if(response.data === 'Something you dont want')
return $q.reject('some error occured');
else{
return $q.resolve(response.data);
}
})
}

You can use de reject method of the $q service to immetiately forward to the next error section, something like:
var deferred = $q.defer();
$http.get(url}.success(function(r) {
deferred.reject();
}).error(function(){
// do something
});
When success q.reject will forward to the error and do something...

As $http is a modified promise do something like :
var deferred = $q.defer();
$http.get(url).success(function(r) {
if(r != 'your criteria')
deferred.reject("Booh");
else
deferred.resolve("Baah");
}).error(function(){
deferred.reject("Beeh");
});
return deferred.promise

Related

How to be explicit in resolving deferred promise in angular $q?

If I have something in my service like
myServiceMethod: function(){
$http.get(myUrl)
.success(function(result){$q.defer().resolve(result);})
.error(function(error){$q.defer().resolve(error);});
return $q.defer().promise;
}
and in my controller
myService.myServiceMethod()
.then(function(result){})
.then(function(error){});
is there a way to be explicit in the name space? Because it seems like the deferred promises can get messy if you start nesting deferred resolve. For example
myServiceMethod: function(){
$http.get(myUrl)
.success(
function(result){
if(result){
$q.defer().resolve(result);
}else{
$q.defer().resolve(myCustomresult);
}
})
.error(function(error){$q.defer().resolve(error);});
return $q.defer().promise;
}
You are creating too many deferred objects and the one being returned is not what you are resolving or rejecting
Just return the $http which itself returns a promise. what you are trying to do is considered an anti-pattern
myServiceMethod: function(){
// return the `$http` promise
return $http.get(myUrl)
.then(function(result){return result.data);})
// either catch it here or catch in controller
.catch(function(error){ alert('Error')});
}
Controller
myService.myServiceMethod()
.then(function(result){})
.catch(function(error){});
Every time you call $q.defer() you are creating a new promise, which isn't the right thing to do.
The $http.get method itself returns a promise, so unless you are doing something else that needs to run asynchronously, you do not need to use $q
For arguments sake, you can do this:
myServiceMethod: function() {
var myPromise = $q.defer();
$http.get(myUrl).success(function(result){
if(result)
myPromise.resolve(result);
else
myPromise.reject(result);
});
return myPromise.promise;
}
Could be much shorter:
Service
myServiceMethod: function () {
return $http.get(myUrl).then(function (response) {
return response.data || myCustomResult; // default result if API returned nothing
});
}
Controller
myService.myServiceMethod()
.then(function (result) { /* do something ... */ })
.catch(function (error) { /* handle error ... */ });

Should I return the result of deferred.resolve/reject?

When working with Q deferreds, should I return the result of deferred.resolve and deferred.reject?
function foo() {
var deferred = Q.defer();
service.doSomethingAsync({
success: function() {
deferred.resolve(); // should I return the result of resolve here?
},
fail: function(err) {
deferred.reject(err); // should I return the result of reject here?
}
});
return deferred.promise;
}
Your code can be changed to:
function foo() {
var deferred = Q.defer();
service.doSomethingAsync({
success: deferred.resolve,
fail: deferred.reject
});
return deferred.promise;
}
What you want to return from the foo() method depends on what you want to achieve of course. In many cases you hide the internals and just return an empty array or null if something fails. But..if it is needed...you can throw an error. If you want to handle things outside the function, yes, return the error object for example...like I said...it depends.

Parse.Promise and angluarjs $q promise

I am trying to use Parse sdk with angularjs and I am a bit confused on handling promises when using implementation of promises in parse and angular.js
Parse promise provides a method fail to catch error where as angularjs provides us with catch. So say if I am inside Parse promise object and have to return say angularjs promise from it or vice versa. It won't have I guess fail method in it
ParsePromise().then(function(){
return angularPromise();
}).fail(function (error){
});
AngularPromise().then(function(){
return ParsePromise();
}).catch(function (error){
});
What should I do in such scenario?
I will suggest to use $q. Just wrap parse promises in angular's $q promises. then use only angularjs promise handling.
findByIdsInParse = function(arr) {
var ParseObject = ParseService.Object.extend('ParseObject');
var deffered = $q.defer();
var query = new ParseService.Query(ParseObject);
query.containedIn('objectId', arr);
query.find({
success: function(data) {
deffered.resolve(data);
},
error: function(error) {
deffered.reject(error);
}
});
return deffered.promise;
};
We can wrap a parse function into a return $q((resolve,reject)=>{}) then we can use them in all $q functions. So something like this:
findTransactionById(id){
return $q((resolve,reject) => {
//... set up variables, queries ...
query.find().then(resolve,reject)
})
}
//we can then use them in all $q functions
findTransactionById(12).
then(console.log)
let promises = [findTransactionById(10),findTransactionById(9)]
$q.all(promises)
.then((values) => {
return findTransactionById(999)
})
.catch(console.error)

$q.reject and handling errors in AngularJS chained promises

I'm having trouble understanding a basic concept of error handling with chaining promises.
In order to learn the rules, I have written a simple example, guessing what the result will be. But unfortunatly it doesn't behave as I though it will.
I have read multiple articles about the subject but perhaps can't I get details because of my poor english language.
Anyway, here is my code :
var promiseStart = $q.when("start");
var promise1 = promiseStart.then(function() {
return Serviceforpromise1.get();
});
var promise2 = promise1.then(function(data1)
{
return Serviceforpromise2.get(data1);
},function(error)
{
return $q.reject();
});
var promiseend = promise2.then(function(data2)
{
return data2;
},function(error)
{
return error;
});
return promiseend;
Well I know that it can be way better coded but it's just for the purpose.
Here is the code of Serviceforpromise1 function :
function Serviceforpromise1()
{
...
return $http.get(*whatever*).then(function (data){
return data;
},function(error)
{
return $q.reject();
});
}
Consider only the case of Serviceforpromise1's failure. A $q.reject is sent back to main chain so I'm waiting the error callback of "promise1 .then(" to be called and it worked as expected. I decided for the example to transfert the error to the "promise2 .then" so in this error callback I added the line return $q.reject();
But it never reached the second error callback (the "promise2 .then" one) and I don't understand why (like Serviceforpromise1, I returned a rejected promise !)
I will be happy to deeply understand what is happening here.
Thanks for your help.
Your understanding is correct, and the problem appears to lie somewhere in the way you are trying to observe this behavior (in something you haven't shown us).
If you return a rejected promise from either a success or error handler in then(), then the promise returned by then() will resolve to a rejected promise. Observe:
angular.module('app', [])
.controller('C', [
'$q',
function ($q) {
var promiseStart = $q.when("start");
var promise1 = promiseStart.then(function (value) {
console.log('Got a value:', value);
return $q.reject('Error!');
});
var promise2 = promise1.then(function (data1) {
return "Got some stuff";
}, function (error) {
console.log("Caught an error:", error);
return $q.reject('New error');
});
var promiseend = promise2.then(function (data2) {
return data2;
}, function (error) {
console.log('Caught an error:', error); // <-- this is logged to the console
return error;
});
return promiseend;
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
<div ng-app='app' ng-controller='C'></div>
One thing to note here is that in that last handler, you are returning the error variable, and not throwing an exception or returning a rejected promise. So in this case, promiseend will successfully resolve with the value of that error variable.

Async.js return promise

I'm using the async.js library to achieve an stream of asynchronous requests.
The code below works fine.
async.each(
//--- Collection of models to save ---//
collSaveData,
function(model, callback){
model.save([], {success: function(){
callback();
}});
},
function(err){
console.log('finished');
});
How can I return a promise?
I mean, something in a fashion like this:
var promise = async.each(
//--- Collection of models to save ---//
collSaveData,
function(model, callback){
model.save([], {success: function(){
callback();
}});
},
function(err){
console.log('finished');
});
You probably don't need async.js to issue you calls and synchronize them. Combine the objects returned by Model.save with $.when to produce a general promise :
var promises = _.invoke(collSaveData, 'save');
var promise = $.when.apply(null, promises);
promise.then(function() {
console.log('all done');
});
And a Fiddle http://jsfiddle.net/nikoshr/Z3Ezw/
You can customize how you handle the responses from each save, for example:
var promises = _.map(collSaveData, function(m) {
return m.save().then(function(response) {
console.log('saved', m);
});
});
The key is to return a promise for each model. http://jsfiddle.net/nikoshr/Z3Ezw/2/
Not actually used async before but looking through the docs it makes no reference to returning a promise so you would have to wrap the asyn.each with a function that did return a promise and then the success/error callback could then just resolve or reject that promise
here is a quick example that should work
//wrap the async each and return a promise from this call
var promiseAsync = function(openfiles, saveFile) {
var defer = $.Deferred();
async.each(
openfiles, saveFile, function(err) {
if (err) {
defer.reject(err);
} else {
defer.resolve();
}
});
return defer.promise();
}
//now it can be used like a normal promise
var promise = promiseAsync(collSaveData, function(model, callback) {
model.save([], {
success: function() {
callback();
}
});
});
$.when(promise).done(function(){
//whatever
}).fail(function(err){
//error
});
make promiseAsync available throughout your app (attach it to Backbone somewhere, underscore mixin,helper/utility module??) and then you can always use it.
Update: fiddle based on #nikoshr's fiddle (for setting up the page) (going to start using fiddles over code pen now like the fact you can have a console in the browser) http://jsfiddle.net/leighking2/7xf7v/

Categories