Recovering from rejected promises in JS

I use native promises (mostly) and try to recover from an error and continue running the promise chain.

In fact, I am doing this:

  • A REST request to find out if an identifier exists. Note that this returns jquery deferred.
  • . then (A success identifier means that there is an error, so it crashes and stops) (no failure identifier, so continue creating the identifier)
  • .then (create an identity and send to the server)

I am returning Promise.resolve () from my rejected function, which should lead to the successful part of the following. then execute. Is not. I tried this on Chrome and Safari.

Please note: the first promise is a pending request, but according to this page ( http://api.jquery.com/deferred.then/ ), pending. then () returns the promise object. Therefore, the addition of additional. Then should be hiding from native promises.

To make this clearer, here's the pseudo code:

promise = $.ajax(url); promise = promise.then(); // convert to promise promise.then(function() { cleanup(); return Promise.reject(); }, function(err) { return Promise.resolve(); }); .then(function() { createIdentityDetails(); }); .then(function() { sendIdentityDetails(); }); 

Note that I want FAIL when ajax returns success, and I want to continue processing when ajax fails.

What happens is that the FAIL function works for all subsequent ones. Then the parts are executed. That is, my return of Promise.resolve () does not work - which (I think) is in violation of the specification.

I would appreciate any feedback on how I can deal with errors in long-term chains and repair them.

Thanks so much for any advice you can provide.

ps the creation and collection of complete identification information takes a lot of time, so I do not want to do this if the ID exists. So I want to check first and work quickly.

pps I really like how promises unwind these deeply nested asynchronous callback chains.

+4
source share
4 answers

Assuming createIdentityDetails() and sendIdentityDetails() are promising asynchronous functions ...

If what we see in the question is a whole chain of promises, then processing the error condition is simple. There is no need to convert success into failure or failure in success, or from one type of promise to another.

 $.ajax(url).then(function() { cleanup(); }, function(err) { createIdentityDetails() .then(sendIdentityDetails); }); 

This will work regardless of the type of promise returned by createIdentityDetails() jQuery or non-jQuery.

If, however, there is more, for example, the caller function should be informed about the results, then you need to do more, and it depends on how you want to report the possible results.

Report id already exists as failure and "new id created as successful

Here is what the question suggests

 function foo() { return $.ajax(url).then(function() { cleanup(); return $.Deferred().reject('failure: ID already exists'); }, function(err) { return createIdentityDetails() .then(sendIdentityDetails) .then(function() { return $.when('success: new ID created'); }); }); } 

Report both types of results as success

This seems more reasonable as the error processed will be reported as successful. Only unpredictable unhandled errors will be reported as such.

 function foo() { return $.ajax(url).then(function() { cleanup(); return 'success: ID already exists'; }, function(err) { return createIdentityDetails() .then(sendIdentityDetails) .then(function() { return $.when('success: new ID created'); }); }); } 

Whatever reporting strategy is adopted, it is very important which type of promise createIdentityDetails() returns. As the first promise in a chain, he defines the behavior of both of his chains.

  • If createIdentityDetails() returns its own ES6 promise, then no worries, most tastes of the promise, even jQuery, will be learned.
  • if createIdentityDetails() returns a jQuery promise, then only jQuery promises will be acquired. Therefore, sendIdentityDetails() should also return a jQuery promise (or an ES6 promise that should be processed into jQuery with $.Deferred(...) ), as well as the final success converter (as mentioned above).

You can see the mix effects of jQuery and ES6 promises in these two ways here . The first warning is generated by the second block of code, and this is not what is expected. The second warning is generated by the first block and correctly gives the result 98 + 1 + 1 = 100.

+1
source

It seems that jQuery promises does not allow you to exchange failure for success. If, however, you use native promises, you can.

For instance:

 Promise.resolve() .then(function() {console.log("First success"); return Promise.reject(); }, function() { console.log("First fail"); return Promise.resolve(); }) .then(function() {console.log("Second success"); return Promise.reject(); }, function() { console.log("Second fail"); return Promise.resolve(); }) .then(function() {console.log("Third success"); return Promise.reject(); }, function() { console.log("Third fail"); return Promise.resolve(); }) 

Here I return the failure of the first success handler. In the second error handler, I return the solution. Everything works as expected. Output: (Chrome):

 First success Second fail Third success 

It turns out that the correct way to handle pending jQuery and promises is to click them:

 var jsPromise = Promise.resolve($.ajax('/whatever.json')); 

(from http://www.html5rocks.com/en/tutorials/es6/promises/ ). This works well, so if you change the starting line above to:

 Promise.resolve($.ajax("this will fail")) ... 

You will receive correctly:

 First fail Second success Third fail 

On the bottom line ... defer a pending promise as soon as possible, then everything seems to work correctly.

+1
source
 promise = promise.then(); // convert to promise 

A? The promise returned by $.ajax is already a promise.

 promise.then(function() { cleanup(); return Promise.reject(); }, function(err) { return Promise.resolve(); }); 

The problem is that jQuery is not Promises / A + compatible and cannot accept promises / thenable from anything other than its own. You should use $.Deferred here to make this work, for example

 promise.then(function() { cleanup(); return $.Deferred().reject(); }, function() { return $.when(); }); // or return $.Deferred().resolve(); 

That is, my return Promise.resolve() does not work - which (I think) is in violation of the specification.

Indeed. However, jQuery is known for this , and they will not fix it until version 3..0.

To get your own Promise library that you want to use, you need to avoid jQuery then . This can be easily done :

 var $promise = $.ajax(url); var promise = Promise.resolve($promise); // convert to proper promise promise.then(function() { cleanup(); throw undefined; }, function(err) { return undefined; }) .then(createIdentityDetails) .then(sendIdentityDetails); 
+1
source

I hope this clarifies the situation a bit, you had a couple of stray; and you do what you really don't need to do in subsequent functions

firstly i'm sure you do NOT want

 promise = promise.then(); 

The code will look like this:

 promise = $.ajax(url); promise.then(function() { cleanup(); throw 'success is an error'; // this is equivalent to return Promise.reject('success is an error'); }, function(err) { return 'failure is good'; // returning here means you've nullified the rejection }) // remove the ; you had on this line .then(function() { createIdentityDetails(); }) // remove the ; on this line .then(function() { sendIdentityDetails(); }) // remove the ; on this line .catch(function(err) { }); // you want to catch the error thrown by success 
0
source

All Articles