I have a function doSomething() that returns a promise chain, utilizing the Q framework. The contents are similar to something like:
loadDataSet : function (params) {
return Q.fcall(function() {
//Do Something
})
.then(function(){
//Do Something Else
throw New Error('unexpected error');
});
}
The calling code goes something like:
var promise = loadDataSet(args);
I want to figure out whether that error was thrown. Notice, in the loadDataSet function implementation, I did not utilize the .done() function.
So far, I have code that looks like this and have been unsuccessful in capturing the error and handling it appropriately (here, the code is modified, slightly from above):
try {
loadDataSet(args)
.catch(function(error) {
return error
})
.done();
}....
The goal is to handle the error from a try-catch block. What am I missing?
Well, this is going to a be a bummer.
You can't
While a lot of promise libraries let you do this and will report unhandled rejections for you - in Q you have no methods to automatically detect these failures.
You have to Use .done or change a promise library. Heck, even native promises are going to be able to do this in a few days.
Q specific solution:
In Q your only realistic option is to use .done, unlike then done is not throw safe and you can throw exceptions from there and they won't be suppressed - this requires you to remember to always terminate chains with done but it works:
myObj.loadDataSet(handleSuccess, handleError).done(); // will throw on rejection
Personally until Q fixes this and other issues I cannot recommend using it to anyone.
Modern libraries and native promises
I've written a specification based on work by Domenic and Petka for promise libraries to be able to report errors globally and hook to them. Several libraries already implement this including bluebird and when. Domenic is working on a parallel specification for web browsers.
Currently supported or are going to be supported in the next few weeks are: bluebird, when, es6-promise, rsvp and native promises in io.
// log any unhandled promise rejections
process.on('unhandledRejection', function(reason, p){
console.log("Possibly Unhandled Rejection at: Promise ", p, " reason: ", reason);
// application specific logging here
});
As for browsers, something like:
window.addEventListener("unhandledrejection", function(e) {
var reason = e.detail.reason;
var promise = e.detail.promise;
console.log("Unhandled rejection", promise, reason);
});
This protocol is less supported but there are plans to include it in native promises. Currently Firefox native promises will report unhandled rejections and Chrome's will attempt too - but there are no browser hooks for it yet (it's coming though).
Note that teams are working on very interesting tooling. After a discussion with Paul Irish I'm convinced great things are going to come our way in terms of tooling for debugging promises in browsers that will make native promises almost as debuggable as bluebird promises (which is awesome!).
You can't throw exceptions inside then as no one will able to catch it. Instead, create a new Q.deferand call reject on it whenever there's an error
loadDataSet : function (params) {
var deferred = Q.defer()
Q.fcall(function() {
//Do Something
}).then(function(){
//Do Something Else
deferred.reject('error message')
}, deferred.reject)
return deferred.promise
}
then use it like this
loadDataSet().then(function (data) {
//ok, got data
}).catch(function (err) {
//error!
})
Related
This question already has answers here:
When is .then(success, fail) considered an antipattern for promises?
(7 answers)
Closed 4 years ago.
I have come across multiple applications where using catch is preferred over rejectHandler.
Eg:
Preferring
new Promise.then(resolveHandler).catch()
instead of
new Promise().then(resolveHandler, rejectHandler).catch()
Is there a particular reason for this??
I find
new Promise().then(resolveHandler, rejectHandler).catch()
to be more useful because
I can use rejectHandler to address designed/expected error scenario where Promise.reject is called.
I can use catch block to address unknown/unexpected programming/runtime errors that occur.
Does someone know any particular reason why rejectHandler is not used much?
P.S. I am aware of newer alternatives in ES6 but I just curious to know this.
Update: I KNOW HOW rejectHandler and catch works. The question is why do I see more people use only catch over both rejectHandler and catch? Is this a best practice or there is some advantage?
Update(Adding answer here): Found the answer I was looking for first hand.
The reason is not just because the error in reject is handled by catch it is mainly because of chaining. When we are chaining promise.then.then.then.then, having a resolve, reject pattern proves a bit tricky to chain it since you wouldn't want to implement a rejecthandler just to forward the rejectData up the chain. Using only promise/then/catch along with resolve/return/throw proves very useful in chaining N numbers of thenables.
#Bob-Fanger(accepted answer) addressed some part of this too.
Eg:
getData(id) {
return service.getData().then(dataList => {
const data = dataList.find(data => {
return data.id === id;
});
if (!data) {
// If I use Promise.reject here and use a reject handler in the parent then the parent might just be using the handler to route the error upwards in the chain
//If I use Promise.reject here and parent doesn't use reject handler then it goes to catch which can be just achieved using throw.
throw {
code: 404,
message: 'Data not present for this ID'
};
}
return configuration;
});
}
//somewhere up the chain
....getConfiguration()
.then(() => {
//successful promise execution
})
.catch(err => {
if (err.code) {
// checked exception
send(err);
} else {
//unchecked exception
send({
code: 500,
message: `Internal Server error: ${err}`
});
}
});
Using just these All I need to worry about is promise/then/catch along with resolve/return/throw anywhere in the chain.
The difference is that if an error occurs inside resolveHandler it won't be handled by the rejectHandler, that one only handles rejections in the original promise.
The rejectHandler is not used in combination with catch that much, because most of the time we only care about that something went wrong.
Creating only one errorhandler makes the code easier to reason about.
If a specific promise in the chain should handled differently that can be a reason to use a rejectHandler, but i'd probably write a catch().then().catch() in that case.
Neither is more useful than the other. Both the rejected handler and the catch callback are called when an error is thrown or a promise is rejected.
There is no "best practice" to use one over the other. You may see code use one or the other, but it's use will be based on what the code needs to achieve. The programmer may want to catch an error at different times in the chain and handle errors thrown at different times differently.
Hopefully the following will help explain what I mean:
somePromise
.then(
function() { /* code when somePromise has resolved */ },
function() {
/* code when somePromise has thrown or has been rejected.
An error thrown in the resolvedHandler
will NOT be handled by this callback */ }
);
somePromise
.then(
function() { /* code when somePromise has resolved */ }
)
.catch(
function() {
/* code when somePromise has thrown or has been rejected OR
when whatever has occurred in the .then
chained to somePromise has thrown or
the promise returned from it has been rejected */ }
);
Notice that in the first snippet, if the resolved handler throws then there is no rejected handler (or catch callback) that can catch the error. An error thrown in a resolved callback will not be caught by the rejectedHandler that is specified as the second argument to the .then
As stated in the post, provision of a resolve and reject handler in the same call to .then allows dealing with rejection of the previous promise separately from errors thrown within, or returning a rejected promise from, the success handler.
Because a rejection handler returning without throwing an error resumes the fufilled channel of a promise chain, a final catch handler will not be invoked if a previous rejection handler returns normally.
The question then devolves into use cases, cost of development and level of knowledge.
Use cases
In theory the two parameter form of then call could be used to retry an operation. But because hard coded promise chains are set up statically, retrying the operation is not simple. An easier way to retry might be to use an async function with try-catch statements surrounding await of a promise that may need to be retried as in this concept code:
async function() {
let retries = 3;
let failureErr = null;
while( retries--) {
try {
var result = await retryableOperationPromise()
return result;
}
catch( err) {
failureErr = err;
}
}
throw failureErr // no more retries
}
Other use cases may not be widespread.
Cost of development or commercial decisions.
If telling a user to retry later is acceptable it may be cheaper than doing anything about specific reasons for promise rejection. For example if I try to book a flight over midnight, when airlines put the prices up, I usually get told "an error occurred, try again later" because the price I was given at the start of booking will not be honored.
Knowledge (<opinion>)
I suspect that promise usage may often be based on example rather than in-depth knowledge of the subject. It is also possible program managers want to keep the code base as simple as possible for less experienced developers (probably a cost issue).
"Best practice" may not truly apply for making decisions on how to use promises if the usage is valid. Some developers and managers will avoid some forms of usage as a matter of principle, but not always based on technical merit.
I am using Oboe.js to parse a really really large JSON file
const promises = [];
oboe('http://domain/my-file.js')
.node('items.*', item => {
// parseItem() returns a rejected Promise because of invalid JSON items
promises.push(parseItem(item));
})
.done(() => {
Promise.all(promises).then(() => {
doSomething();
});
})
But my Browser console gets flooded with Uncaught (in promise). The same occurs if you write a promise in a setTimeout() like
const promises = [];
setTimeout(() => {
promises.push(Promise.reject());
}, 500);
// some time in the future
Promise.all(promises);
What's really strange: modern browsers behave differently. In Firefox Developer Edition everything works without the error messages and in Chrome I get flooded with Uncaught (in promise). In Chrome you get the message instantly if you write Promise.reject(); without a catch. In Firefox and Safari nothing happens.
So what's the solution for this? Ignoring the message? I mean if this behavior is really in the official promise spec then promises in asynchronous code does not make really sense for me.
Your Oboe issue is based on the fact Oboe streams JSON in, so we never know in advance how many promises there are so we can't attach the responsibility to Promise.all in advance. We can "promisify" Oboe to be able to return promises in its methods.
Typically, I'd use RxJS to automatically create a stream from the event emitter -and RxJS's methods can already return promises and then aggregate it. However - since I don't want a third party library here, and it has less teaching value - let's implement it ourselves:
function addMap(oboe) {
oboe.map = function(selector, mapper){
var promises = [];
return new Promise(function(resolve, reject){ // create a new promise
oboe.node(selector, function(match){
var result = mapper(match); // get result
// signal that we're handling the rejection to make sure it's not handled.
result.catch(function(){});
promises.push(result);
});
oboe.fail(reject);
oboe.done(function(){ resolve(promises); });
});
};
}
Which would let us do:
var o = oboe("foo");
addMap(o);
o.map("items.*", item => downloadItem(item)).then(result => {
// handle result here
});
Your setTimeout issue is very contrived. The vast majority of people do not write code that looks like this in practice - in practice adding a error handler asynchronously is a pretty rare use case when not working against an API that forces you to do so (like the Oboe.js example).
What's really strange: modern browsers behave differently
This is because Firefox uses GC for detecting unhandled rejections and Chrome a timer. It's implementation detail - the only guarantee you'll have is that errors will not be logged if attached within a microtask (synchronously, or in a then that executes on the same turn).
Here it is recommended to end promises chain with done methods for the error be re-thrown:
The Golden Rule of done vs. then usage is: either return your promise
to someone else, or if the chain ends with you, call done to terminate
it. Terminating with catch is not sufficient because the catch handler
may itself throw an error.
Is it applied to AngularJs? I've looked and there is seems to be no such method in the framework.
UPDATE:
I've taken look at the code and found the following:
try {
if (isFunction(fn)) {
promise.resolve(fn(state.value));
} else if (state.status === 1) {
promise.resolve(state.value);
} else {
promise.reject(state.value);
}
} catch (e) {
promise.reject(e);
exceptionHandler(e);
}
window.onerror = function(e) {
// doesn't come here
}
So basically angular additionally logs the error from the promise handler in exceptionHandler(e); so it doesn't go unnoticed. If needed, default exceptionHandler's behaviour can be over-ridden as explained here.
done() method on Promises/A+ specification
Notice that Promises does only specify then, it says nothing about done.
Q recommends to… What about usage in Angular?
Q is not $q! There is no done method on Angular's promise implementation, so I would recommend not to use it.
The golden rules of Q do not apply to Angular, they have largely different features.
Promises are asynchronous, so you cannot use a try catch statement around the callbacks. done is used for throwing an unrecoverable, uncatchable to the environment (so window.onerror or process.onuncaughtexception would be called).
If you want to catch exceptions, you should use the catch method with a callback:
$q.reject(new Error()).catch(function(e) {
console.log("does catch an error");
});
To catch unhandled rejections (at the end of your promise chains), you also can use $exceptionHandler.
Angular use $q which is :
an implementation of promises/deferred objects inspired by Kris Kowal's Q.
You need to use the Promise API provided in angular documentation : .finally(), .then(), and .catch().
Angular describe such difference quite well :
Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains all the important functionality needed for common async tasks.
So looks like there is no .done() in $q.
Hope it answers your question.
In addition to sebastienbarbier's answer, the $q angular service is also tied into the $digest cycle (that angular runs internally) and which (for $q) performs the function of .done() in Kris Kowal's Q.
This can catch you out in tests, where a $scope.digest() ensures that the promises are fully resolved.
I am trying to understand how to debug asynchronous code that is based on promises. By Promises I mean ECMAScript 6 based promises and by debugging I mean using the built-in chrome or firefox debugger.
What I am having trouble with - is that when an error occurs I can't seem to get the stack trace no matter how I 'reject' it.
I tried these:
console.log(new Error('Error occured'));
throw new Error('Throwing an Error');
return new Error('Error returned by the onRejected function');
reject(new Error('Pass Error to the reject function'));
But none of those returns the actual error in the code, or the stack trace.
So my question is - how to properly debug javascript Promises?
This is a great topic to discuss, the sad news are this is actually quite hard with native promises.
Debugging raw ES6 promises in Chrome is horrible. This is because they will silently suppress errors and whenever you omit a catch it will not give you any indication that the promise failed. Update: Chrome now logs unhandled rejections (see this link for how)
Promise.resolve("foo").then(function(){
throw new Error("You will never see this");// silent failure
});
In Firefox, things are a bit better since they perform unhandled rejection detection - however, it's still flakey and if you assigned the promise anywhere it won't work.
So, what can be done?
Include Bluebird - it's a superset of ES6 promises and you can swap it right inside, it has a richer API, it's faster and it has amazing stack traces. It's built with debugging in mind and includes great error handling facilities.
Once you've included Bluebird, call:
Promise.longStackTraces();
Which will slow it down a bit (it'll still be very fast) and will give you amazing error messages. For example:
Promise.resolve().then(function outer() {
return Promise.resolve().then(function inner() {
return Promise.resolve().then(function evenMoreInner() {
a.b.c.d()
});
});
});
In native promises - this will be a silent failure and will be very hard to debug - with Bluebird promises this will show a big red error in your console by default giving you:
ReferenceError: a is not defined
at evenMoreInner (<anonymous>:6:13)
From previous event:
at inner (<anonymous>:5:24)
From previous event:
at outer (<anonymous>:4:20)
From previous event:
at <anonymous>:3:9
at Object.InjectedScript._evaluateOn (<anonymous>:581:39)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:540:52)
at Object.InjectedScript.evaluate (<anonymous>:459:21)
Once you're done debugging - you can swap it out and go back to native promises. Personally I value knowing I have errors in production so I don't recommend it but it's certainly doable.
This answer is an addition to Benjamin Gruenbaum's answer:
If you use a catch statement in the promise chain, you'll get the stack trace by error.stack:
Promise.longStackTraces();
function outer() {
return Promise.resolve();
}
function inner() {
return Promise.resolve();
}
function evenMoreInner() {
a.b.c.d()
}
Promise.resolve()
.then(outer)
.then(inner)
.then(evenMoreInner())
.catch(function (err) {
console.log(err.message);
console.log(err.stack);
});
Error Message:
ReferenceError: a is not defined
at evenMoreInner (test/test_promise.js:58:17) <<<< HERE's the error!
at Context.<anonymous> (test/test_promise.js:64:23)
*This doesn't directly answer your question, but it may be helpful nonetheless.
Chrome devtools recently got a new feature that's useful for debugging async code, such as Promises.
http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/
Basically, enable the "async" checkbox in the sources tab, and Chrome will reconstruct the call stack for you as if it were synchronous code.
They seem to be working with debug tools in Chrome. See this thread for more info.
https://code.google.com/p/v8/issues/detail?id=3093
I havn't checked if this is already in the dev version or beta version but I hope it will be soon. It might then be included in the normal version in January 2015 or so (just a personal guess, absolutley no promise since I don't even work for Google).
The best way to debug promised is to listen to unhandledRejection event of your process.
For example, here is how you might set it up and dump a stack trace...
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
// Stack Trace
console.log(reason.stack);
});
Inside .then() function when the Promise object is returned,
add a console.log() statement.
Do the same inside .catch() if needed:
...
.then(
(docs) =>{
console.log(docs); ==> put here
resolve(docs);
})
.catch((e)=>{
From what I have understood there are three ways of calling asynchronous code:
Events, e.g. request.on("event", callback);
Callbacks, e.g. fs.open(path, flags, mode, callback);
Promises
I found the node-promise library but I don’t get it.
Could someone explain what promises are all about and why I should use it?
Also, why was it removed from Node.js?
Since this question still has many views (like mine) I wanted to point out that:
node-promise looks rather dead to me (last commit was about 1 year ago) and contains nearly no tests.
The futures module looks very bloated to me and is badly documented (and I think that the naming conventions are just bad)
The best way to go seems to be the q framework, which is both active and well-documented.
Promises in node.js promised to do some work and then had separate callbacks that would be executed for success and failure as well as handling timeouts. Another way to think of promises in node.js was that they were emitters that could emit only two events: success and error.
The cool thing about promises is you can combine them into dependency chains (do Promise C only when Promise A and Promise B complete).
By removing them from the core node.js, it created possibility of building up modules with different implementations of promises that can sit on top of the core. Some of these are node-promise and futures.
A promise is a "thing" which represents the "eventual" results of an operation so to speak. The point to note here is that, it abstracts away the details of when something happens and allows you to focus on what should happen after that something happens. This will result in clean, maintainable code where instead of having a callback inside a callback inside a callback, your code will look somewhat like:
var request = new Promise(function(resolve, reject) {
//do an ajax call here. or a database request or whatever.
//depending on its results, either call resolve(value) or reject(error)
//where value is the thing which the operation's successful execution returns and
//error is the thing which the operation's failure returns.
});
request.then(function successHandler(result) {
//do something with the result
}, function failureHandler(error) {
//handle
});
The promises' spec states that a promise's
then
method should return a new promise that is fulfilled when the given successHandler or the failureHandler callback is finished. This means that you can chain together promises when you have a set of asynchronous tasks that need to be performed and be assured that the sequencing of operations is guaranteed just as if you had used callbacks. So instead of passing a callback inside a callback inside a callback, the code with chained promises looks like:
var doStuff = firstAsyncFunction(url) {
return new Promise(function(resolve, reject) {
$.ajax({
url: url,
success: function(data) {
resolve(data);
},
error: function(err) {
reject(err);
}
});
};
doStuff
.then(secondAsyncFunction) //returns a promise
.then(thirdAsyncFunction); //returns a promise
To know more about promises and why they are super cool, checkout Domenic's blog : http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/
This new tutorial on Promises from the author of PouchDB is probably the best I've seen anywhere. It wisely covers the classic rookie mistakes showing you correct usage patterns and even a few anti-patterns that are still commonly used - even in other tutorials!!
http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html
Enjoy!
PS I didn't answer some other parts of this question as they've been well covered by others.
Mike Taulty has a series of videos, each of them less than ten minutes long, describing how the WinJS Promise library works.
These videos are quite informative, and Mike manages to show the power of the Promise API with a few well-chosen code examples.
var twitterUrl = "http://search.twitter.com/search.json?q=windows";
var promise = WinJS.xhr({ url: twitterUrl });
promise = promise.then(
function (xhr) {
},
function (xhr) {
// handle error
});
The treatment of how exceptions are dealt with is particularly good.
In spite of the WinJs references, this is a general interest video series, because the Promise API is broadly similar across its many implementations.
RSVP is a lightweight Promise implementation that passes the Promise/A+ test suite. I quite like the API, because it is similar in style to the WinJS interface.
Update Apr-2014
Incidentally, the WinJS library is now open source.
Another advantage of promises is that error handling and exception throwing and catching is much better than trying to handle that with callbacks.
The bluebird library implements promises and gives you great long stack traces, is very fast, and warns about uncaught errors. It also is faster and uses less memory than the other promise libraries, according to http://bluebirdjs.com/docs/benchmarks.html
What exactly is a Promise ?
A promise is simply an object which represents the result of an async operation. A promise can be in any of the following 3 states :
pending :: This is the initial state, means the promise is neither fulfilled nor rejected.
fulfilled :: This means the promise has been fulfilled, means the value represented by promise is ready to be used.
rejected :: This means the operations failed and hence can't fulfill the promise.
Apart from the states, there are three important entities associated to promises which we really need to understand
executor function :: executor function defines the async operation which needs to be performed and whose result is represented by the promise. It starts execution as soon as the promise object is initialized.
resolve :: resolve is a parameters passed to the executor function , and in case the executor runs successfully then this resolve is called passing the result.
reject :: reject is another parameter passed to the executor function , and it is used when the executor function fails. The failure reason can be passed to the reject.
So whenever we create a promise object, we've to provide Executor, Resolve and Reject.
Reference :: Promises
I've been also looking into promises in node.js recently. To date the when.js seems to be the way to go due to its speed and resource use, but the documentation on q.js gave me a lot better understanding. So use when.js but the q.js docs to understand the subject.
From the q.js readme on github:
If a function cannot return a value or throw an exception without
blocking, it can return a promise instead. A promise is an object that
represents the return value or the thrown exception that the function
may eventually provide. A promise can also be used as a proxy for a
remote object to overcome latency.
Promise object represents the completion or failure of an asynchronous operation.
So in order to implement a promise, you need two parts:-
1.Creating Promise:
The promise constructor accepts a function called an executor that has
2 parameters resolve and reject.
function example(){
return new Promise (function(resolve , reject){ //return promise object
if(success){
resolve('success'); //onFullfiled
}else{
reject('error'); //onRejected
}
})
}
2.Handling Promise:
Promise object has 3 methods to handle promise objects:-
1.Promise.prototype.catch(onRejected)
2.Promise.prototype.then(onFullfiled)
3.Promise.prototype.finally(onFullfiled,onRejected)
example.then((data) =>{
//handles resolved data
console.log(data); //prints success
}).catch((err) => {
//handles rejected error
console.log(err); //prints error
})