1

While working with Promise and async/await as it's executor function in an example, I observed a behavior which I can'e understand clearly. On executing either of following cases throws "UnhandledPromiseRejectionWarning" warning:

Case-1

new Promise(async function(resolve, reject) {
    var x = await new Promise(
        function(res, rej) {setTimeout(function() { rej("3b") }, 2000) 
    });
    resolve(x);
}).then(function(result) {
    console.log("3b. Result: " + result);
}).catch(function(err) {
    console.log("3b. Error: " + err);
});

Case-2

new Promise(async function(resolve, reject) {
    var x = await new Promise(
        function(res, rej) { throw "3c" }
    );
    resolve(x);
}).then(function(result) {
    console.log("3c. Result: " + result);
}).catch(function(err) {
    console.log("3c. Error: " + err);
});

However if I enclose the async function's code block in try-catch like:

new Promise(async function(resolve, reject) {
    try {
        var x = await new Promise(
            function(res, rej) { throw "3c" }
        ); 
        resolve(x);
    }
    catch (err) {
        reject(err);
    }
}).then(function(result) {
    console.log("3c. Result: " + result);
}).catch(function(err) {
    console.log("3c. Error: " + err);
});

It outputs "3c. Error: 3c"(similarly for Case-1, the output becomes "3b. Error: 3b" after applying try-catch).

On the other hand if I use similar async function inside then handler and without try-catch, it doesn't cause any "UnhandledPromiseRejectionWarning":

Case-3

new Promise(async function(resolve, reject) {
    var x = await new Promise(
        function(res, rej) { setTimeout(function() { res("3d-1") }, 1000) }
    );
    return resolve(x);
}).then(async function(result) {
    console.log("3d-1. Result: " + result);
    var x = await new Promise(function(res, rej) { setTimeout(function() { rej("3d-2") }, 2000) });
    return x;
}).then(function(result) {
    console.log("3d-2. Result: " + result);
}).catch(function(err) {
    console.log("3d. Error: " + err);
});

Case-4

new Promise(async function(resolve, reject) {
    var x = await new Promise(function(res, rej) { setTimeout(function() { res("3e-1") }, 1000) });
    return resolve(x);
}).then(async function(result) {
    console.log("3e-1. Result: " + result);
    var x = await new Promise(function(res, rej) { throw "3e-2" }); // Throwing error from timer can't be handled and hence program crashes.
    return x;
}).then(function(result) {
    console.log("3e-2. Result: " + result);
}).catch(function(err) {
    console.log("3e. Error: " + err);
});

Here it outputs: 3d-1. Result: 3d-1, 3d. Error: 3d-2 for Case-3(and similar for Case-4).

As we can see Case-3 and Case-4 are quite similar with Case-1 and Case-2 respectively, with the difference that the rejection(or throw) now happens inside then block. Here I don't put the rejection blocks inside try-catch but still it works.

Someone please help me understand this behavior of async-await and Promise.
Thanks in advance.

Mintu Kumar
  • 101
  • 4
  • 2
    Javascript best practice is to use `async` functions *or* `new Promise`: not both. I'm not sure if this is the cause of your problem, but it would be sensible either way. – lonesomeday Oct 01 '18 at 13:00
  • I don't understand why you want to use "Promise in Promise", of course you know there are many articles on web but (https://codeburst.io/a-simple-guide-to-es6-promises-d71bacd2e13a) is good article. – KnowGe Oct 01 '18 at 13:02
  • @KnowGe The example I have shown is not an actual use case, but there was a situation where the executor function of outermost Promise needed to make some API calls before marking it as resolved. For making the API calls I used axios which is a Promise based library. Though I didn't want to use "new Promise(...)" syntax again to make API calls and do the required processing before marking the outermost Promise resolved. I wanted to use the simplified version of Promise handling i.e. asyn-await scheme for making the API requests and that was the time I observed the issue which I mentioned. – Mintu Kumar Oct 01 '18 at 13:08
  • @MintuKumar Every API call should produce its own promise, and the "outermost" function should not use the `new Promise` constructor at all but just do promise chaining (using `then` or `await`). – Bergi Oct 01 '18 at 13:10
  • @Bergi Thanks for helping me visualizing the behavior. I am having more clear idea and will strictly avoid such scenario. Thanks again. – Mintu Kumar Oct 01 '18 at 13:35

0 Answers0