Skip to content

Instantly share code, notes, and snippets.

@yiminghe
Created February 2, 2012 11:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yiminghe/1723027 to your computer and use it in GitHub Desktop.
Save yiminghe/1723027 to your computer and use it in GitHub Desktop.
promise using Q about error propagation
var d = Q.defer(),
ret = [],
p = d.promise;
var p2 = p.then(
function (v) {
ret.push("e1 :" + v);
throw "e1";
},
function (r) {
ret.push("e2 :" + r);
return "e2";
});
var p3 = p2.then(
function (v) {
ret.push("e3 :" + v);
throw "e3";
},
function (r) {
ret.push("e4 :" + r);
return "e4";
});
var p4 = p3.then(function (v) {
ret.push("e5 :" + v);
throw "e5";
}, function (r) {
ret.push("e6 :" + r);
return "e6";
});
setTimeout(function () {
d.resolve(1);
}, 100);
setTimeout(function () {
alert(ret.join("\n"));
}, 200);
@yiminghe
Copy link
Author

yiminghe commented Feb 2, 2012

expected:
e1:1
e4:e1
e6:e4

actual result:
e1:1
e4:e1
e5:e4

@yiminghe
Copy link
Author

yiminghe commented Feb 2, 2012

KISSY's result is what i want:

    var d = KISSY.Defer(),
            ret = [],
            p = d.promise;

    var p2 = p.then(
            function (v) {
                ret.push("e1 :" + v);
                throw "e1";
            },
            function (r) {
                ret.push("e2 :" + r);
                return "e2";
            });

    var p3 = p2.then(
            function (v) {
                ret.push("e3 :" + v);
                throw "e3";
            },
            function (r) {
                ret.push("e4 :" + r);
                return "e4";
            });

    var p4 = p3.then(function (v) {
        ret.push("e5 :" + v);
        throw "e5";
    }, function (r) {
        ret.push("e6 :" + r);
        return "e6";
    });

    setTimeout(function () {
        d.resolve(1);
    }, 100);

    setTimeout(function () {
        alert(ret.join("\n"));
    }, 200);

@domenic
Copy link

domenic commented Feb 2, 2012

Why would you expect e6: e4?

Consider:

var p4 = p3.then(function (v) {
    ret.push("e5 :" + v);
    throw "e5";
}, function (r) {
    ret.push("e6 :" + r);
    return "e6";
});

p3 is a fulfilled promise, since the error handler does return "e4" instead of re-throwing. This signals successful recovery, just like not rethrowing in a catch block.

Thus, the fulfillment handler for p3 will be run with the value p3 is fulfilled with, viz. "e4". So "e5 :e4" is as expected.

To get your expected behavior, just re-throw instead of recovering: change line #22 to throw "e4" instead of return "e4".

@domenic
Copy link

domenic commented Feb 2, 2012

To be further illustrative, your code is the equivalent of:

function p() {
  return 1;
}

function p2() {
  var v;
  try {
    v = p();
  } catch (r) {
    ret.push("e2 :" + r);
    return "e2";
  }

  ret.push("e1 :" + v);
  throw "e1";
}

function p3() {
  var v;
  try {
    v = p2();
  } catch (r) {
    ret.push("e4: " + r);
    return "e4";
  }

  ret.push("e3 :" + v);
  throw "e3";
}

function p4() {
  var v;
  try {
    v = p3();
  } catch (r) {
    ret.push("e6 :" + r);
    return "e6"; 
  }

  ret.push("e5 :" + v);
  throw "e5";
}

p4();

As you can see, the code path that gets followed is:

  • p() executes without errors; `"e1 :1"
  • p2() then throws "e1"
  • So p3's catch clause gets entered: "e4: e1"
  • That catch clause returns "e4", i.e. p3() returns "e4"
  • So p4's catch clause is never entered: "e5 :e4".

@yiminghe
Copy link
Author

yiminghe commented Feb 3, 2012

@DomenicDenicola :

Thank you , i misunderstood the error callback of promise at first, i thought it is just used for error propagation and notification.

Now i see it can also be used for recovery :)

@domenic
Copy link

domenic commented Feb 3, 2012

@yiminghe happy to help! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment