How can I catch rejected Promises? - javascript

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.

Related

How to handle errors with Async and Await [Node.js]

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;
}

rejected Promise in try-catch with/without await

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.

Connection is not defined in oracledb

I am using the oracledb cen node.js module and when making a database connection to make a select, it returns the data but this error also appears:
(node:1) UnhandledPromiseRejectionWarning: ReferenceError: connection is not defined
at Object.getTest (/home/src/storage/oracleDb.js:29:9)
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch().
(rejection id: 1)
(node:1) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I do the query like this:
try {
await oracledb.getConnection(config.db)
.then(function (conn) {
return conn.execute(querys.queryTest());
}, function(err) {
console.log(err);
})
.then(function (result) {
console.log('Query executed');
console.log(result.rows[0]);
}, function(err) {
console.log(err);
})
.catch(function(err) {
console.log(err);
});
} catch (error) {
console.log(error);
} finally {
if (connection) {
try {
await connection.close();
} catch (err) {
console.error(err);
}
}
}
If you can use await, then you're in an async function. If you're in an async function, why are you using promise chains?
Here's what this type of code would look like with Promises:
const oracledb = require('oracledb');
function getEmployee(empId) {
return new Promise(function(resolve, reject) {
let conn; // Declared here for scoping purposes.
oracledb
.getConnection()
.then(function(c) {
console.log('Connected to database');
conn = c;
return conn.execute(
`select *
from employees
where employee_id = :emp_id`,
[empId],
{
outFormat: oracledb.OBJECT
}
);
})
.then(
function(result) {
console.log('Query executed');
resolve(result.rows[0]);
},
function(err) {
console.log('Error occurred', err);
reject(err);
}
)
.then(function() {
if (conn) {
// If conn assignment worked, need to close.
return conn.close();
}
})
.then(function() {
console.log('Connection closed');
})
.catch(function(err) {
// If error during close, just log.
console.log('Error closing connection', err);
});
});
}
module.exports.getEmployee = getEmployee;
And here's what it would look like with async/await:
const oracledb = require('oracledb');
function getEmployee(empId) {
return new Promise(async function(resolve, reject) {
let conn; // Declared here for scoping purposes.
try {
conn = await oracledb.getConnection();
console.log('Connected to database');
let result = await conn.execute(
`select *
from employees
where employee_id = :emp_id`,
[empId],
{
outFormat: oracledb.OBJECT
}
);
console.log('Query executed');
resolve(result.rows[0]);
} catch (err) {
console.log('Error occurred', err);
reject(err);
} finally {
// If conn assignment worked, need to close.
if (conn) {
try {
await conn.close();
console.log('Connection closed');
} catch (err) {
console.log('Error closing connection', err);
}
}
}
});
}
module.exports.getEmployee = getEmployee;
See this series for more info:
https://jsao.io/2017/06/how-to-get-use-and-close-a-db-connection-using-various-async-patterns/
You can try add connection to a variable declared outside try-catch block, something like below:
let connection;
try {
await oracledb.getConnection(config.db)
.then(function (conn) {
// this is where you assign the connection value to a variable
connection = conn;
return conn.execute(querys.queryTest());
}, function(err) {
console.log(err);
})
.then(function (result) {
console.log('Query executed');
console.log(result.rows[0]);
}, function(err) {
console.log(err);
})
.catch(function(err) {
console.log(err);
});
} catch (error) {
console.log(error);
} finally {
// this if should be fine now
if (connection) {
try {
await connection.close();
} catch (err) {
console.error(err);
}
}
}
I would suggest to read about scoping in javascript, it might help you for future problems. Here's a link: https://www.w3schools.com/js/js_scope.asp

mongoose Chaining with then and catch

How To Convert This Function to Chaining with then and catch?
Is better to Chained?
I mean User.findOne().then().catch()
User.findOne({_id: msg.chat.id}, (err, doc) => {
if (err) {
console.log(err);
}
if (doc) {
console.log(doc.name);
} else {
console.log('Empty');
}
});
The function you pass to then is called with the returned document (or null) if the operation succeeds, and the catch is called with the error if the operation fails (e.g. no connection). Putting it together looks like this:
User.findOne({_id: msg.chat.id})
.then(doc => {
if (doc) {
console.log(doc.name);
} else {
console.log('Empty');
}
}).catch(err => {
if (err) {
console.log(err);
}
});
As an aside, when you are searching for one document by id, then you can use findById:
User.findById(msg.chat.id)
.then(doc => {
if (doc) {
console.log(doc.name);
} else {
console.log('Empty');
}
}).catch(err => {
if (err) {
console.log(err);
}
});
Better switch to ES2017 async/await syntax, you can avoid Promise Hell
async function foo () {
try {
var doc = await User.findOne({_id: msg.chat.id}).exec()
if (doc)
return console.log(doc.name);
console.log('Empty');
} catch (err) { console.log(err) }
}
foo()
This will help you when you're going to nest DB calls or using for...loops.
async function foo () {
try {
var users = await User.find({}).exec()
for (var user in users) {
var tweets = await Tweet.find({_user: user._id}).exec()
user.tweets = tweets.map(t => t.text)
await user.save()
}
} catch (err) { console.log(err) }
}
foo()

Bluebird.js: Re-Throwing the error in catch callback is not caught again

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);
});

Categories

Resources