How to reject (and use correctly) Promises?

Story:

  • Speaking of Promises / A + , what is the right way to reject a promise - throw an error? But if I miss catch , my application will explode!

  • How to use promisify and what are its advantages (you may need to read a longer version)?

  • Is .then(success, fail) really anti-pattern and should I always use .then(success).catch(error) ?

A longer version, described as a real life problem (I would like someone to read):

I have a library that uses Bluebird (A + Promise implementation library) to retrieve data from a database (speaking of Sequelize ). Each query returns a result, but sometimes it is empty (tried to select something, but it wasn’t). A promise is included in the result function because there is no reason for the error (having no results, this 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 up and check if the result is empty (I can't check it everywhere in my code). I have done 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 either sql error OR there is no result! }); 

If you are still with me - I hope you understand what happened. I want to somehow run the error function (where is the "ERROR function"). The fact is that I do not know how to do this. I 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 from my comments (and by spec), throwing an error works well. But there is a big one , but - if I skipped the .catch instruction, the whole application will explode.

Why don't I want this? Let's say I want to increase the counter in my database. I don't care about the result - I'm just making an HTTP request. Therefore, I can call incrementInDB() , which has the ability to return results (even for testing reasons), so there is a throw new Error if it did not work. But since I don’t need an answer, sometimes I won’t add the .catch operator , right? But now - if I fail (by appointment or fault) - I end up with your node application down.

I do not find it very pleasant . Is there a better way to work, or do I just need to deal with it?

My friend helped me, and I used a new promise to rectify the situation, for example:

 function findFirst() { var deferred = new Promise.pending(); // doesnt' matter if it 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 } 

It works like a charm! But I realized: Promise Anti Patterns is a wiki article written by Petka Antonov, creator of Bluebird (A + implementation). He clearly said that this was not true .

So my second question is this? If so, why? And what's the best way?

Thanks so much for reading this, I hope someone takes the time to answer it for me :) I have to add that I did not want to depend too much on frameworks, so Sequelize and Bluebird are just the things that I ended up working with. My problem is Promises as a global, not a specific framework.

+8
javascript promise bluebird
source share
2 answers

Please ask only one question per post :-)

Is .then(success, fail) really an anti-pattern and should I always use .then(success).catch(error) ?

Not. They just do different things , but as soon as you know you can choose the right one.

How to use promisify and what are its benefits?

I think the Bluebird Promisification docs explains this pretty well - he used the api callback transform that returns promises.

Speaking of Promises / A +, what is the right way to reject a promise - throw an error?

Yes, throwing an error is completely fine. Inside the callback then you can drop and it will be automatically caught, which will lead to the rejection of the promise of the result.

You can also use return Promise.reject (new Error(…)); ; both will have exactly the same effect.

My friend helped me, and I used a new promise to rectify the situation, for example: [...]

Not. You really shouldn't use this . Just use then and drop or return the rejected promise there.

But if I miss the expression on the trick, my application will explode!

No, it will not. Note that the .catch() method is not a try catch expression - an error will already be detected where your then callback was called. Then it is passed only in response to catch as an argument; a call to .catch() not required to write exceptions.

And when you skip .catch() , your application will not hit. All that happens is that you have a rejected promise around which the rest of your application will not be affected. You will receive an unprocessed rejection event that can be viewed globally .

Of course, this should not be; each promise chain ( not every promise instance) must end with .catch() , which handles errors accordingly. But you definitely don't need .catch() in every helper function, when it returns a promise somewhere else, then the errors are usually handled by the caller.

+8
source share

Speaking of Promises / A +, what is the right way to reject a promise - throw an error? But if I miss the trick, my whole application will explode!

And if you use return codes to signal errors instead of exceptions, a lack of verification will lead to subtle errors and erratic behavior. Forgetting to handle errors is a mistake, but if your application is exploded in such an unsuccessful case, it is often better than letting it continue to work in a damaged state.

Debugging a forgotten error code check, which is obvious only to an application that behaves strangely in some place unrelated to the source code, is easily many orders of magnitude more expensive than debugging a forgotten catch, because you have an error message, the source of the error and tracing stack. Therefore, if you want to increase productivity in a typical application development scenario, exceptions win a fairly large margin.

. then (success, failure)

This is usually a signal that you are using promises as illustrious callbacks, where callbacks are simply passed separately. This is obviously an anti-pattern, since you will not get any benefits from using promises in this way. If this is not the case, even then you just make your code a little less readable than using .catch() , just like method(true, true, false) much less readable than method({option1: true, option2: true, option3: false}) .

How to use promisify and what are its advantages (maybe you will need to read a longer version)?

Most modules only open the callback interface, promisify automatically turns the callback interface into the promise interface. If you write such code manually (using deferred or new Promise ), you are wasting your time.

So my second question is this? If so, why? And what's the best way?

The best way is to make a promise:

 function findFirst() { return Entity.find(1).tap(function(result) { if (!result) throw new Error("no result"); }); } 

This is better because it is a simpler, shorter, more readable, and much less error prone way to do the same.

+5
source share

All Articles