CC-Archived / promise-as3

Promises/A+ compliant implementation in ActionScript 3.0
167 stars 52 forks source link

When error happened in fullfilled function, it's not caught. #28

Closed koshuang closed 10 years ago

koshuang commented 10 years ago

When there is an error in fullfilled function, we can't know error happened.

sample code:

var dfd:Deferred=new Deferred();

dfd.promise.then(function() {
    trace("true");
    throw new Error();
},
function(){
    trace("false");
});

setTimeout(function(){
    dfd.resolve("");
}, 3000);

It only shows "true" in console but gets no error message.

johnyanarella commented 10 years ago

This behavior is intentional (and specifically required by the Promises/A+ specification) because it allows Promise chains to recover and raise errors akin to try..catch in synchronous code.

The onFulfilled and onRejected callbacks are more than just a place to put code that you want to execute when a Promise is resolved or rejected. The callbacks you register using then() are actually used to transform that Promise's resolved value or rejection reason as a new Promise. This allows you to do things like: inspect a successful response object for an error code and turn that into an error when one is present, or transform an error into an alternative operation or fallback value.

How does that work?

promise.then( onFullfilled, onRejected ) returns a new Promise of the resolved value or rejection reason as transformed by those callbacks. If you return a value in your callback, the new Promise is resolved with that value. If you throw an error the new Promise is rejected with that value. That applies to both callbacks.

Example 1. Transforming a resolved value into a rejection by throwing an error from an onFulfilled callback:

(These are a little verbose to help with clarity.)

var deferred:Deferred = new Deferred();

var transformedPromise = deferred.promise.then(
    function () {
        // This will be called.

        // Throwing an error will reject transformedPromise.
        throw new Error();
    },
    function () {
        // This will not be called.
    }
);

transformedPromise.then(
    function () {
        // This will not be called.
    },
    function () {
        // This will be called with error thrown in the onResolved callback above.
    }
);

setTimeout(function(){
    deferred.resolve("value");
}, 3000);

Example 2. Transforming a rejection into a resolved value (i.e. recovery) by returning a value from an onRejected callback:

var deferred:Deferred = new Deferred();

var transformedPromise = deferred.promise.then(
    function () {
        // This will be not be called.
    },
    function () {
        // This will be called, but we can recover!

        // This will resolve transformedPromise with a value.
        return "fallback value";
    }
);

transformedPromise.then(
    function ( value ) {
        // This will be called with value returned in the onRejected callback above.
    },
    function () {
        // This will not be called.
    }
);

setTimeout(function(){
    deferred.reject(new Error());
}, 3000);

Now... to your underlying concern: while you are developing, how do you detect unexpected or unhandled errors that are being inadvertently swallowed as rejections?

promise-as3 adds some helpful methods you may be unaware of - log() and done().

log() will trace out the result of a Promise and done() will cause unhandled rejections to be rethrown as traditional errors. You can place log() anywhere in your Promise chain, but done() should only be used at the end a Promise chain.

Please refer to the documentation for these two methods for more details:

I think those are what you are really looking for.

Best regards! Thanks for checking out promise-as3.