6

All:

I am pretty new to Promise, here is an example:

var someAsyncThing = function() {
  return new Promise(function(resolve, reject) {
    // this will throw, x does not exist
    resolve(x + 2);
  });
};

var someOtherAsyncThing = function() {
  return new Promise(function(resolve, reject) {
    reject('something went wrong');
  });
};

someAsyncThing().then(function() {
  return someOtherAsyncThing();
}).catch(function(error) {
  console.log('oh no', error);
});

I do not quite get how .then() works with Promise, right now I can understand the someAsyncThing() return a Promise, which will generate an exception and thus go to .catch() part. And if we change resolve(x+2) to resolve(4), then it will go to run someOtherAsyncThing(); and return another promise,

the first question is if the return of .then() is the that Promise?

And second question, if in someOtherAsyncThing()'s Promise, I use resolve(x+2) to cause an exception, then it will also go to same .catch() part, then how can I make that .catch() only catch exception caused by someAsyncThing()'s promise(and same question for chained .then() if there is any)?

Thanks

Kuan
  • 11,149
  • 23
  • 93
  • 201
  • The catch will catch any exception in the chain, in order to get more rich information about the exception, or to do something different depending on which promise threw the exception you'd have to reject with information that you'd then handle in the catch block. – Z2VvZ3Vp Dec 12 '15 at 00:25
  • @PixMach Thanks, got it. This is really flexible and hard to use it proficiently. – Kuan Dec 12 '15 at 00:37

3 Answers3

4

the first question is if the return of .then() is the that Promise?

p.then() returns a promise - always. If the callback passed to the .then() handler returns a value, then the newly returned promise will be resolved at the same time as the parent promise, but will be resolved with the returned value from the handler.

If the .then() handler returns a promise, then the promise returned by .then() is not fulfilled/rejected until the promise returns by the handler is fullfilled/rejected. They are chained together.

If the .then() handler throws, then the promise returned by .then() is rejected with the exception as the value. Throwing is the same as returning a rejected promise.

if in someOtherAsyncThing()'s Promise, I use resolve(x+2) to cause an exception, then it will also go to same .catch() part, then how can I make that .catch() only catch exception caused by someAsyncThing()'s promise(and same question for chained .then() if there is any)?

The beauty of promises is that errors propagate up the chain until handled. The way you stop err propagation at any level is to handle the error there.

If you want to separate the .catch() opportunities, then you have to just catch at a lower level. For example:

someAsyncThing().then(function() {
  return someOtherAsyncThing().catch(function(err) {
      // someOtherAsyncThing rejected here
      // you can handle that rejection here and decide how you want to proceed

      // for example, suppose you just want to handle the rejection, log it
      // and then continue on as if there was no problem, you can just return
      // a value here
      return 0;
  });
}).catch(function(error) {
  console.log('oh no', error);
});
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Thanks, got it. This is really flexible and a little hard to understand. Do you have any links which talk about Promise and then() very easy to understand ? – Kuan Dec 12 '15 at 00:34
  • @Kuan - I don't have a favorite reference. This looks like it covers things pretty well: http://trevorburnham.com/presentations/flow-control-with-promises/#/. If you just follow the questions here with the `promise` tag, you will also learn a lot as you will find authors and supporters of major promise libraries answering questions here or commenting on things. – jfriend00 Dec 12 '15 at 00:39
  • @Kuan: https://github.com/kriskowal/q/wiki/General-Promise-Resources. And of course I can recommend [my answer to *Aren't promises just callbacks?*](http://stackoverflow.com/a/22562045/1048572) as well as [this one on control flow with `then` and `catch`](http://stackoverflow.com/q/24662289/1048572) – Bergi Dec 17 '15 at 05:10
3

Errors bubble up in promises until they're caught.

If you have the following (<= indicates contains):

Promise1 <= Promise2.catch(e) <= Promise3 <= throw

Then Promise3 throws and rejects. Promise2 rejects and then is caught. Promise1 resolves successfully because it receives no rejection.

Promise1 <= Promise2.catch(e) <= Promise3 <= throw
^ resolves  ^ rejects            ^ rejects

Think of it as an async try/catch.

Promise1 = Promise.reject(err); // or throw

Promise2 = Promise1.catch(err => {
  // error caught
});

Promise3 = Promise1.catch(err => {
  throw err;
  // error not caught but thrown back
});

// Now Promise1 is rejected. Promise2 is resolved. Promise3 is rejected.

You also need to know that each then/catch call creates a new Promise. I suggest you read the Promises/A+ spec and keep it as a reference.

Louay Alakkad
  • 7,132
  • 2
  • 22
  • 45
  • Thanks, is the Promise created by then/catch same as the one returned by someOtherAsyncThing() in my case? – Kuan Dec 12 '15 at 00:39
  • Nope. Each `then/catch` creates a new promise. And each `then` callback is run on `nextTick`, so it's not even a sync operation. Read the spec, it's really handy :) – Louay Alakkad Dec 12 '15 at 00:41
  • Also in your case, `someOtherAsyncThing` promise does not even exist when you call the `catch` method. Remember that calling `then/catch` is a sync operation while cloning promises is an async one. – Louay Alakkad Dec 12 '15 at 00:44
  • I don't understand the terminology "bubble" or "contain". –  Dec 12 '15 at 05:16
  • `promise1 = promise.then(() => promise2);` Here you can say `promise1` contains `promise2` because `promise1` has to wait for `promise2` to settle before it itself settles. Maybe "contains" is not the best word here but that's how things visually are to me. Bubbling is similar to [event delegation](https://davidwalsh.name/event-delegate) in DOM. – Louay Alakkad Dec 12 '15 at 14:51
2

You can catch() on the inner Promise:

a().then(function() {
  return b().catch(function() {
    console.log('boo');
  });
}).catch(function(error) {
  console.log('oh no', error);
});

If a() rejects, "oh no" will be logged. If b() rejects, "boo" will be logged, but not "oh no".

Félix Saparelli
  • 8,424
  • 6
  • 52
  • 67