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.
Related
What are the differences between Mozilla's JavaScript docs' Promises (see API page) and jQuery's Promises (see API page)?
Mozilla's promise seems to have only 2 methods: then and catch. jQuery's promise seems to have more methods, including: then, done, and fail. (from here)
How come the JS API on Mozilla doesn't have done()? What if I want to have a done() functionality in JavaScript? What do I do?
Mozilla's javascript promises are based on ES6 standard, whereas jQuery promises were something created before ES6 was released.
Based on my reading of the jQuery docs, ES6 then is equivalent to jQuery done.
There are actually a boatload of promise libraries, but to me the ES6 one is the simplest to understand. You don't need more than "then" and "catch" and it is real easy to chain together into a sequence of operations. Add to that with Promise.all for parallel tasks and 99% of what you need is covered.
return doSomething().then(function(result) {
return doSomethingElse(result);
}).then(function(secondResult) {
return doThirdSomething(secondResult);
}).catch(function(err) {
console.log(err);
}).then(function(finalResult) {
// a then after a catch is like a "finally" or "always"
return finalResult;
});
Some things that jQuery does support that is not in ES6 is some sort of "progress" resolve.
jQuery's deferred API is bloated and predates promise libraries. Once they realised how useful promises were, they added a then (or previosly, pipe) method, however it they failed to get it 100% right.
How come the JS API on Mozilla doesn't have done()?
It's completely unnecessary. All Promises/A+ compatible implementations (which includes ES6) only need a single method: .then(). It's completely universal, you can do everything with it - it's the primitive of promises.
What if I want to have a done() functionality in JavaScript? What do I do?
Well, you could implement it yourself:
Promise.prototype.done = function(cb) { // or function(...cbs) for (let cb of cbs) …
this.then(cb).then(null, function(err) { /* ignore */ });
return this;
};
But as you can see from that, it's not very useful actually. It doesn't chain, and it ignores exceptions, so you should just use then everywhere.
I can speak for why ES6 don't have .done. However, you can still have something that's akin to .done.
yourPromiseObject.then(successHandler).catch(failureHandler).then(doneHandler);
The first then handles a success response, but will not be called with the yourPromiseObject's function rejects or throw exception. The second catch is critical in "resolving" any exceptions/rejection (in short, you tell the promise object to keep going, you know that there's an error). Make sure you return something valid, even something as simple as the failureHandler consist of nothing but a return 0 will work. The final .then is now guaranteed to be called, so that's your .done
Assuming I have a function which calls two dependend async functions
function targetFn() {
asyncFn1();
asyncFn2();
}
This is clearly a defect, since asyncFn2 does not wait for asyncFn1 to be completed. The correct implementation would be:
function targetFn() {
asyncFn1().then(asyncFn2);
}
However, how to test this? Maybe I test it like this:
it("ensures the ordering", function() {
spyOn(window, "asyncFn1").and.callFake(function() {
return $q.reject("irrelevant");
});
spyOn(window, "asyncFn2");
$timeout.flush();
expect(asyncFn2).not.toHaveBeenCalled();
});
This is okay for this simple test case. But what if I have several chained async functions? The test effort would grow exponential; I have to test every possible combination of rejection and resolving for every promise. What if I change a sync function so that it is an async function afterwards? I would introduce a defect behavior in every callee function without any failing tests.
What I really want is an automatic detection of unhandled promises. Going back to the first example:
function targetFn() {
asyncFn1();
asyncFn2();
}
The test system should recognizes that asyncFn1 and asyncFn2 are creating new promises, but that there are no then and catch handler. Also the second example should of course fail:
function targetFn() {
asyncFn1().then(asyncFn2);
}
Because the then introduces a new promise which is not handled, since it is not returned.
I would like to write a test like:
it("does not introduce unhandled promises", function() {
expect(targetFn).doesNotIntroduceUnhandledPromises();
});
And it checks if every promise created during the execution of targetFn has either an "endpoint" like a finally or is chained to the promises returned by the targetFn.
Do you have any idea how to achive this? Or even a better solution for this?
Thanks
Timo
This is clearly a defect, since asyncFn2 does not wait for asyncFn1 to be completed. The correct implementation would be:
No it's not, it's pretty common to want to perform two operations in parallel, or even downright ignore one's result:
function loadNewData() {
reportDataLoadedToGoogleAnalytics();
return dataService.loadNewData("someParameter");
}
Your issue though, is that your promises aren't being returned. As a rule of thumb whenever a method performs something async with promises, it should return a promise. That would effectively eliminate your problem of testing interesting promises (return them in mocha)
What I really want is an automatic detection of unhandled promises.
That's actually quite possible, you can either use a powerful library like bluebird and swap out $q and use its built in facilities or decorate $q yourself. However when I tried to do these decorations it ended up so hacky I begged satan to take my soul (had to do new Error().stack and grep it for a function name).
Short story:
Talking about Promises/A+, what is the proper way to reject a promise - throwing an error? But if I miss the catch - my whole app will blow!
How to use promisify and what are the benefits of it (maybe you'll need to read the longer version)?
Is .then(success, fail) really an anti-pattern and should I always use .then(success).catch(error)?
Longer version, described as real life problem (would love someone to read):
I have a library that uses Bluebird (A+ Promise implementation library), to fetch data from database (talking about Sequelize). Every query returns a result, but sometimes it's empty (tried to select something, but there wasn't any). The promise goes into the result function, because there is no reason for an error (not having results is not an error). Example:
Entity.find(1).then(function(result) {
// always ending here, despite result is {}
}).catch(function(error) {
// never ends here
});
I want to wrap this and check if the result is empty (can't check this everywhere in my code). I did this:
function findFirst() {
return Entity.find(1).then(function(result) {
if (result) { // add proper checks if needed
return result; // will invoke the success function
} else {
// I WANT TO INVOKE THE ERROR, HOW?! :)
}
}).catch(function(error) {
// never ends here
});
}
findFirst().then(function(result) {
// I HAVE a result
}).catch(function(error) {
// ERROR function - there's either sql error OR there is no result!
});
If you are still with me - I hope you will understand what's up. I want somehow to fire up the error function (where "ERROR function" is). The thing is - I don't know how. I've tried these things:
this.reject('reason'); // doesn't work, this is not a promise, Sequelize related
return new Error('reason'); // calls success function, with error argument
return false; // calls success function with false argument
throw new Error('reason'); // works, but if .catch is missing => BLOW!
As you can see by my comments (and per spec), throwing an error works well. But, there's a big but - if I miss the .catch statement, my whole app blows up.
Why I don't want this? Let's say I want to increment a counter in my database. I don't care about the result - I just make HTTP request.. So I can call incrementInDB(), which has the ability to return results (even for test reasons), so there is throw new Error if it failed. But since I don't care for response, sometimes I won't add .catch statement, right? But now - if I don't (on purpose or by fault) - I end up with your node app down.
I don't find this very nice. Is there any better way to work it out, or I just have to deal with it?
A friend of mine helped me out and I used a new promise to fix things up, like this:
function findFirst() {
var deferred = new Promise.pending(); // doesnt' matter if it's Bluebird or Q, just defer
Entity.find(1).then(function(result) {
if (result) { // add proper checks if needed
deferred.resolve(result);
} else {
deferred.reject('no result');
}
}).catch(function(error) {
deferred.reject('mysql error');
);
return deferred.promise; // return a promise, no matter of framework
}
Works like a charm! But I got into this: Promise Anti Patterns - wiki article written by Petka Antonov, creator of Bluebird (A+ implementation). It's explicitly said that this is wrong.
So my second question is - is it so? If yes - why? And what's the best way?
Thanks a lot for reading this, I hope someone will spent time to answer it for me :) I should add that I didn't want to depend too much on frameworks, so Sequelize and Bluebird are just things that I ended up working with. My problem is with Promises as a global, not with this particular frameworks.
Please ask only a single question per post :-)
Is .then(success, fail) really an anti-pattern and should I always use .then(success).catch(error)?
No. They just do different things, but once you know that you can choose the appropriate one.
How to use promisify and what are the benefits of it?
I think the Bluebird Promisification docs explain this pretty well - it's used to convert a callback api to one that returns promises.
Talking about Promises/A+, what is the proper way to reject a promise - throwing an error?
Yes, throwing an error is totally fine. Inside a then callback, you can throw and it will be caught automatically, resulting to the rejection of the result promise.
You can also use return Promise.reject(new Error(…));; both will have absolutely the same effect.
A friend of mine helped me out and I used a new promise to fix things up, like this: […]
No. You really shouldn't use that. Just use then and throw or return a rejected promise in there.
But if I miss the catch statement - my whole app will blow!
No, it won't. Notice that .catch() method is not a try catch statement - the error will already be caught where your then callback was invoked. It is then only passed to the catch callback as an argument, the .catch() call is not required to capture exceptions.
And when you miss .catch(), your app won't blow. All what happens is that you have a rejected promise laying around, the rest of your app won't be affected by this. You will get an unhandled rejection event, which can be dealt with globally.
Of course, that should not happen; every promise chain (not every promise instance) should be ended with a .catch() that handles errors appropriately. But you definitely don't need .catch() in every helper function, when it returns a promise to somewhere else then errors will usually be handled by the caller.
Talking about Promises/A+, what is the proper way to reject a promise - throwing an error? But if I miss the catch - my whole app will blow!
And if you use return codes to signal errors instead of exceptions, missing the check will cause subtle bugs and erratic behavior. Forgetting to handle errors is a bug, but having your app blow up in such an unfortunate case is more often better than letting it continue in corrupted state.
Debugging forgotten error code check that is only apparent by the application behaving weirdly at some unrelated-to-the-source-of-error place is easily many orders of magnitude more expensive than debugging a forgotten catch because you have the error message, source of error and stack trace. So if you want productivity in typical application development scenario, exceptions win by a pretty huge margin.
.then(success, fail)
This is usually signal that you are using promises as glorified callbacks where the callbacks are simply passed separately. This is obviously an anti-pattern as you will not get any benefits from using promises in this way. If that's not the case, even then you are just making your code slightly less readable compared to using .catch(), similar to how method(true, true, false) is much less readable than method({option1: true, option2: true, option3: false}).
How to use promisify and what are the benefits of it (maybe you'll need to read the longer version)?
Most modules only expose a callback interface, promisify turns a callback interface automatically into a promise interface. If you are writing such code manually (using deferred or new Promise), you are wasting your time.
So my second question is - is it so? If yes - why? And what's the best way?
The best way is to chain the promise:
function findFirst() {
return Entity.find(1).tap(function(result) {
if (!result) throw new Error("no result");
});
}
It's better because it's simpler, shorter, more readable and far less error-prone way to do exactly the same thing.
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!
})
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
})