1

I am a beginner to the weird ways Javascript works, and I am unable to understand the single threaded design and how Promises work.

Take the following code:

function a() {
  return new Promise((resolve, reject) => {
   var inn = new Promise((resolve, reject) => {
          setTimeout(() => reject('Error'), 0);
        }).catch((msg) => console.log(msg));
    return inn;
  });
}

a().then((msg) => console.log('then'));

My questions are the following:

  • The inner promise fails thats why I get Error printed, but why doesn't the other Promise resolve and get 'then' printed?
  • Does returning a Promise from a Promise means that the outer promise resolves ?
  • When I encounter a catch block does it mean the Promise is cancelled ?

Sorry if this is noob but I am unable to exactly find the answers that I looking for, most other posts are just confusing me.

ng.newbie
  • 2,807
  • 3
  • 23
  • 57

3 Answers3

1

Using new Promise within another new Promise is an antipattern, and what you experience here is a reason why.

You don't call any of the resolve and reject of the outer new Promise. The return inn has no effect, because the outer new Promise is only resolved or rejected, by either calling resolve, reject or by an error that is thrown, and neither of this is happening there.

That's how it should look like:

function a() {
  return new Promise((resolve, reject) => {
    setTimeout(() => reject('Error'), 0);
  }).catch((msg) => console.log(msg));
}

a().then((msg) => console.log('then'));

You only use new Promise if you need to convert something async that does not provide a Promise as a result, into a Promise. And you want to keep the code footprint within that new Promise as small as possible, so that you can be sure that every code path will lead to either a resolve ar reject condition.

So turning a setTimeout into a Promise by wrapping it into a new Promise is fine. But at that point, you have a Promise, so there is no need to wrap that into another new Promise. That breaks the whole purpose of chaining and the guarantees Promises make. (What is the explicit promise construction antipattern and how do I avoid it?)

And you should not use strings as errors. Neither for throw nor for reject use reject(new Error('Error')) (or a custom error object) instead.

t.niese
  • 39,256
  • 9
  • 74
  • 101
  • Can you please explain why it is an anti-pattern (with an example if possible)? – Aditya Bhave Dec 31 '19 at 10:14
  • @AdityaBhave why would you use a promise inside a promise? Kills the purpose of promise chaining. – Yousaf Dec 31 '19 at 10:16
  • Hmm ... makes sense ... I am not able to think of a suitable usecase for it. – Aditya Bhave Dec 31 '19 at 10:18
  • @AdityaBhave `I am not able to think of a suitable use case for it.` there is absolutely no use case. Every use case you might come up with can most certainly be translated from `new Promise((…) => { new Promise((…) => {…}) })` to a `new Promise((…) => {…}).then((…) => new Promise( (…) => {… }))` and if not then its locially broken in some way. – t.niese Dec 31 '19 at 10:32
  • @t.niese I am exploring this nested pattern because I want to understand about Promise behavior. – ng.newbie Dec 31 '19 at 11:05
  • @ng.newbie you shouldn't try to explore behavior that is not an intended use case. It's like - bad comparison incoming - figuring out how a padlock behaves, if you _"lock"_ the fence close by instead of the gate . – t.niese Dec 31 '19 at 11:19
  • @t.niese I get it. But I am actually trying to wrap my head around how Microtasks work in the Javascript event loop. – ng.newbie Jan 01 '20 at 08:39
  • @ng.newbie but even then you shouldn't do that. The `(resolve, reject) => ...` callback you pass to a `new Promise` is called immediately, and has nothing to do with microtasks, only the resolving and rejecting has. You might draw the wrong conclusions out of that. – t.niese Jan 01 '20 at 10:18
0

You must resolve inn within function a rather than return it in order for the promise chain to continue unbroken.

pkfm
  • 451
  • 3
  • 7
0

Because first promise is not resolved/rejected. Check following. I just changed return inn to resolve(inn)

function a() {
  return new Promise((resolve, reject) => {
   var inn = new Promise((resolve, reject) => {
          setTimeout(() => reject('Error'), 0);
        }).catch((msg) => console.log(msg));
    resolve(inn);
  });
}

a().then((msg) => console.log('then'));
Aditya Bhave
  • 998
  • 1
  • 5
  • 10