Exception gets swallowed in the promise chain

I noticed something very strange when an exception is thrown inside the promises chain in Parse for React Native. The chain of promises never decides and never is rejected, and the exception is never thrown. He just disappears silently.

Here is a sample code to recreate the problem:

// Replacing this with Promise.resolve() prints the error. // Removing this stage prints the error. Parse.Promise.as() // Removing this stage causes a red screen error. .then(function() { // Replacing this with Parse.Promise.as() causes a red screen error. return Promise.resolve(); }) .then(function () { throw new Error("There was a failure"); }) .then(function () { console.log("Success")}, function (err) { console.log(err) }); 

As can be seen from the comments, this only happens in this particular sequence of events. Deleting a scene or replacing a Parse promise for a native JS promise makes everyone behave again. (In my actual code, the “Promise.resolve ()” step is actually a call to the native iOS method, which returns a promise.)

I know that Parse promises does not behave exactly like A + -compatible promises ( cf.qaru.site/questions/453696 / ... ). Indeed, by calling Parse.Promise.enableAPlusCompliant() before this section of code causes the exception to be caught and printed. But I thought that Parse promises and native JS promises could be safely used together.

Why does this exception disappear silently?

Thanks.

+5
source share
2 answers

Why does this exception disappear?

Parse by default does not catch exceptions, but promises swallows them.

Parse is not 100% Promises / A + compatible, but nonetheless it tries to assimilate thenables that return from then callbacks. And it does not throw exceptions and does not execute its own callbacks asynchronously.

What you do can be reproduced without then using

 var p1 = new Parse.Promise(); var p2 = new Parse.Promise(); // p2 should eventually settle and call these: p2._resolvedCallbacks = [function (res) { console.log("Success") }]; p2._rejectedCallbacks = [function (err) { console.log(err) }]; function handler() { throw new Error("There was a failure"); } // this is what the second `then` call sets up (much simplified): p1._resolvedCallbacks = [function(result) { p2.resolve(handler(result)); // throws - oops }]; // the native promise: var p = Promise.resolve(); // what happens when a callback result is assimilated: if (isThenable(p)) p.then(function(result) { p1.resolve(result); }); 

The problem is that p1.resolve is synchronous and immediately calls back to p1 - which in turn throws. Throwing p2.resolve before p2.resolve can be called, p2 will remain forever. The exceptions are bubbles and become the completion of p1.resolve() - which now throws a callback to its then method. The original promise implements the exception and rejects the promise returned then with it, which, however, is ignored everywhere.

soundlessly?

If your implementation of the native promise supports raw rejection warnings, you should be able to see the exception hanging in the rejected promise.

0
source

For your consideration, in addition to the technical reasons indicated in your quoted answer:

Matching promises

ES6 / A + compatible Promise instances:

  • When a promise is resolved, its condition and value are unchanged.
  • A promise cannot be kept with a promise.
  • Then, the registered listener "execute" is never called with a promise (or other subsequent) object as an argument.
  • The listeners registered then execute asynchronously in their thread after the code that caused them to execute has completed.
  • Regardless of whether the listener has been registered for a call back when the promise is settled (“fulfilled” or “rejected”),

    • listener return value is used to fulfill the resolution of the promise returned by its registration then
    • the value passed (using throw ) by the listener is used to reject the promise returned by then , and
  • A promise resolved by a Promise instance is synchronized with the possible resolved state and value of the promise provided as an argument. (In the ES6 standard, this is described as "blocked").

  • A promise resolved with a subsequent object that is not a Promise instance will skip synchronization as needed: if it is resolved first with thenable, which “fulfills” itself with thenable, the Promise promise will be re-synchronized with the last 'thenable'. A transition to a new synchronization cannot happen with A + promises, because they never call an "executable" listener followed by an object.

Not compatible promises

Potential characteristics of incompatible promising properties include

  • letting you change the state of a promised promise,
  • calling an "executed" listener with a promise argument,
  • calling the listener, either for "worked out" or "dropped" states, synchronously from the code that allows or rejects the promise,
  • does not reject the returned promise then after the listener registered in the then call throws an exception.

Interoperability

Promise.resolve can be used to repay a promised promise with a static value, possibly mainly used in testing. Its main goal, however, is to quarantine the side effects of incompatible promises. The promise returned by Promise.resolve( thenable) will display all behaviors 1-7 above, and none of the incompatible behaviors.

IMHO I suggest using only non-a + objects on both sides in the environment and according to the documentation for the library that created them. An unauthorized thenable can be used to resolve an A + promise directly (which Promise.resolve does), but for complete predictability of behavior, it must be wrapped in a Promise object using Promise.resolve( thenable) before any other use.

Note. I tried checking Parse promises for A + compliance, but does not seem to provide a constructor. This leads to the fact that claims “almost” or “completely” match A + is difficult to quantify. Thanks to zangw to indicate the possibility of returning a rejected promise to form a listener as an alternative to exception.

0
source

Source: https://habr.com/ru/post/1240817/


All Articles