The only difference between demo1 & demo2 is that demo2 add a await. How come demo1 did't catch the error and demo2 did?
// demo1
try {
new Promise((resolve, reject) => {
resolve()
}).then(() => { throw new Error('haha') }) // Promise: {status: "rejected", value: Error: haha }
console.log('irene test') // print 'irene test', execution is over.
} catch(err) { // didn't catch the error
console.log('irene')
console.log(err)
}
// demo2
try {
await new Promise((resolve, reject) => {
resolve()
}).then(() => { throw new Error('haha') })
console.log('irene test') // didn't print 'irene test'
} catch(err) { // catch the error
console.log('irene') // print 'irene'
console.log(err) // print err
}
In demo1, control flow exits try catch block right after console.log('irene test'). So before you throw an error in Promise, it moves forward. See below.
try{
new Promise((resolve, reject) => {
resolve()
}).then(() => { throw new Error('haha')})
console.log('irene test')
} catch(err) { // catch the error
console.log('irene') // print 'irene'
console.log(err) // print err
}
console.log('already here')
result image
You can see error is thrown after 'already here' is printed.
In demo2, as you know, promise remains in try catch block until error is thrown. (because that's what await do)
Additionally, if you want to print 'irene test' even if there is an error, it's better to use .catch.
new Promise((resolve, reject) => {
resolve()
}).then(() => { throw new Error('haha')
}).catch(err => console.error(err))
console.log('irene test')
It successfully catches error, and also able to print 'irene test'.
The only difference is that this code:
try {
new Promise((resolve, reject) => {
resolve()
}).then(() => { throw new Error('haha') }) // Promise: {status: "rejected", value: Error: haha }
console.log('irene test') // print 'irene test', execution is over.
} catch(err) { // didn't catch the error
console.log('irene')
console.log(err)
}
is equal to this one:
const someFunction = () => { throw new Error('haha') }
try {
new Promise((resolve, reject) => {
resolve()
}).then(someFunction.bind(this)) // Promise: {status: "rejected", value: Error: haha }
console.log('irene test') // print 'irene test', execution is over.
} catch(err) { // didn't catch the error
console.log('irene')
console.log(err)
}
And as you can see here the someFunction has different scope than the try catch.
Related
I have already a function written with bluebird promises and I would like to rewrite it with async and await. When I have made the changes I have found out that earlier with promises the reject statement always transfers the control to called function catch block though if the catch block is already there in the file from where we are rejecting. How to handle this situation properly with async and await?. (Added comments to the code to explain the issue)
With Promise:
const callingFunc = (req, res) => {
return new Promise((resolve, reject) => {
// execute request which returns promise
functionCall()
.then((response) => {
let error;
try {
xml2js(response.body, { explicitArray: false }, (err, result) => {
if (err) {
return reject(err); /* throws the correct error to catch block of the file from where callingFunc is called*/
}
if (!_.isEmpty(result.Response.errorCode)) {
return reject(result.Response); /* throws the correct error to the catch block of the file from where callingFunc is called*/
}
return resolve(result);
});
} catch (e) {
error = new Error('xml2js conversion error');
reject(error);
}
})
.catch((error) => {
const Error = new Error('Internal Server Error');
reject(Error);
});
});
};
With async and await:
const callingFunc = (req, res) => {
try {
const response = await functionCall();
let error;
try {
xml2js(response.body, { explicitArray: false }, (err, result) => {
if (err) {
throw (err); /* throws the error to the below catch block and returning xml2js conversion error and changing behaviour*/
}
if (!_.isEmpty(result.Response.errorCode)) {
throw result.Response; /* throws the error to the below catch block and returning xml2js conversion error and changing behaviour*/
}
return result;
});
} catch (e) {
error = new Error('xml2js conversion error');
throw error;
}
} catch(error) {
const Error = new Error('Internal Server Error');
throw Error;
}
};
If functionCall returns a promise, then this code is inappropriate...
return new Promise((resolve, reject) => {
// execute request which returns promise
functionCall()
.then((response) => {
If xml2js is async using callbacks, then it is appropriate to wrap it in a promise...
// return a promise that resolves with the result of xml2js
async function xml2js_promise(body) {
return new Promise((resolve, reject) => {
xml2js(body, { explicitArray: false }, (err, result) => {
if (err) reject(err);
else if (!_.isEmpty(result.Response.errorCode)) reject(result.Response);
else resolve(result);
});
});
}
Now we can await these. There's no need to nest the try's. (And you only need the try if you're going to do something on the catch).
async callingFunction = (req, res) => {
try {
const response = await functionCall();
} catch (error) {
// do something with this error
}
try {
const result = await xml2js_promise(response.body)
} catch(error) {
// do something with this error
}
return result;
}
My code is as follows:
errorTest().then((result) => {
try {
console.log(result);
}
catch (err) {
console.error("Error detected 1");
console.error(err);
}
}).catch((err) => {
console.error("Error detected 2");
console.error(err);
});
async function errorTest() {
return new Promise((resolve, reject) => {
reject("my error");
})
}
Currently, it prints "Error detected 2".
I would like to catch my error using try / catch such that the code prints "Error detected 1".
How do I modify my code to do this?
first when you declare async function that means you declare a function that returns a Promise. so you don't need to warp it with new Promise
you can just do
async function errorTest() {
throw new Error("my error")
}
then you can catch it with try catch like this
(async () =>{
try{
await errorTest()
}
catch(err){
console.log(err)
}
})()
then the full code will look like this
async function errorTest() {
throw new Error("my error")
}
(async () =>{
try{
await errorTest()
}
catch(err){
console.log(err)
}
})()
The problem is that an error is being thrown in the errorTest function, which happens first, that means that the .catch function is called instead of .then.
async function errorTest() {
return new Promise((resolve, reject) => {
reject("my error");
})
}
try {
var result = await errorTest()
try {
console.log(result);
} catch (err) {
console.error("Error detected 2");
console.error(err);
}
} catch (err) {
console.error("Error detected 1");
console.error(err);
}
you can do something like this
//no need to make it async
function errorTest() {
return new Promise((resolve, reject) => {
reject("my error");
})
}
async function test(){
try{
await errorTest();
try{
console.log(result);
//try some syncronous task.
}
catch(e){
console.error("Error detected 1");
console.error(err);
}
}
catch(err){
//if promise returned by errorTest() is rejected; rejected value: err
console.error("Error detected 2");
console.error(err);
}
}
test(); //this also returns a promise though.
Hope, this helps.
I am having some trouble understanding Javascript promises, specifically chaining them and passing errors up the chain. In the following code:
function myPromise() {
return new Promise((resolve, reject) => {
setTimeout(function() {
console.log('done')
reject('resolved');
}, 1000);
});
}
function myOtherPromise() {
return new Promise((resolve, reject) => {
myPromise().then(done => {
resolve(done);
}).catch(e => {
console.log('In myOtherPromise, caught err: ', e);
reject(e)
});
});
}
myOtherPromise().then(done => {
console.log('done calling myOtherPromise: ', done);
}).catch(e => {
console.log('caught err from myOtherPromise', err);
});
The output shows:
done
In myOtherPromise, caught err: resolved
I don't understand why the following is not printed:
'caught err from myOtherPromise'
I feel like there is something fundamental I am not quite getting. Why doesn't the rejection from myOtherPromise get passed to the final catch block?
You catch the error into the e variable, but output the err variable (which is undefined and causes runtime error).
.catch(e => {
console.log('caught err from myOtherPromise', err);
})
Should be:
.catch(e => {
console.log('caught err from myOtherPromise', e);
})
Here is the code in question:
new Promise((resolve, reject) => {
const opts = {
credentials: 'same-origin',
};
fetch(`/_api/myAPI`, opts)
.then((res) => {
if (!res.ok) {
reject(res);
} else {
...
If the url throws an exception a 401, when the execution reaches reject(res); it throws Uncaught (in promise)
Even after I add a .catch after the .then call, i.e.
fetch(`/_api/myAPI`, opts)
.then((res) => {
if (!res.ok) {
reject(res);
} else {
...
})
.catch((e) => {
console.log(e);
}
it still happens.
Why reject will throw this exception and how can I fix it? My experience is limited to jQuery.Promise and I don't a reject within a failure handler will trigger this error.
When you're rejecting the promise, you're immediately rejecting the promise that is wrapping that entire operation, so you would never get to that catch block.
An analogy: reject and resolve are to promises as return is to functions.
I think what you are trying to do is the code below.
new Promise((resolve, reject) => {
const opts = {
credentials: 'same-origin',
};
fetch(`/_api/myAPI`, opts)
.then((res) => {
if (!res.ok) {
return Promise.reject()
} else {
...
resolve(...);
})
.catch((e) => {
console.log(e);
reject();
}
}
I'm wondering why the outer catch callback is never called in this example:
var returnPromise = function () {
return new Promise(function (resolve, reject) {
resolve('promise return value');
})
};
returnPromise().then(function () {
returnPromise().then(function() {
throw new Error('hello');
}).catch(function (err) {
console.log('got inner error', err);
return Promise.reject(err);
//throw err;
});
}).catch(function (err) {
console.log('got outer error', err);
});
I tried to throw the caught error again and also to return a rejected Promise but in both cases the outer callback is not called.
Can anyone tell me why?
Live Example using bluebird.js 3.0.2:
http://codepen.io/jjd/pen/wMqEpR?editors=001
EDIT: I forgot to return returnPromise() in line 7, that's why the code doesn't work as expected.
A rejected promise is not an error. You can turn an error into a rejected promise - and that's what you do in:
.catch(function (err) {
return Promise.reject(err);
});
and after that it's no longer an error condition. If you want an error condition, don't catch and reject.
function returnPromise() {
return Promise.resolve('promise return value');
}
returnPromise().then(function () {
return returnPromise().then(function () {
throw new Error("failed");
})
}).catch(function (err) {
console.error("Outer: " + err);
});
If your catch handler just does some logging and you want to keep the error then simply rethrow it.
returnPromise().then(function () {
return returnPromise().then(function () {
throw new Error("failed");
}).catch(function (err) {
console.error("Inner: " + err);
throw err; // or new Error('...')
});
}).catch(function (err) {
console.error("Outer: " + err);
});
Thank to #Tomalak that i understand the problem now. Throw error inside then() will return Promise.reject(err) automatically
Promise.reject() inside then() will not return this Promise.reject() automatically.
we must return Promise.reject() explicitly
// Caught
Promise.resolve(10)
.then(() => {
throw new Error("hello"); // Auto return a reject promise
})
.catch(err => {
console.log(err);
});
// Uncaught error
Promise.resolve(10)
.then(() => {
Promise.reject("hello"); // Error happens => no catch happen
})
.catch(err => {
console.log(err);
});
// Caught
Promise.resolve(10)
.then(() => {
return Promise.reject("hello"); // Explicit return Promise.reject()
})
.catch(err => {
console.log(err);
});