Handle UnhandledPromiseRejectionWarning in a function calling another functions - node.js

I am having problems do handle UnhandledPromiseRejectionWarning in a function that call other functions making axios request.
const getCode = async () => {
const code = await baseURL.get('/gcs/login/k?codigoCanal=4')
return code
}
const posLogin = async (code) => {
const poslogin = await baseURL.get(`/resource/autenticar/${code}`)
return poslogin
}
const login = async () => {
try {
const code = await getCode();
const finishedLogin = async posLogin(code)
} catch (error) {
handleLoginError(error)
}
}
const handleLoginError = (error) => {
if (error.response.status === 400) {
throw new Error(`Bad Request; ${error.response.statusText}`)
}
if (error.response.status === 401) {
throw new Error(`Wrong credentials; ${error.response.statusText}`)
}
throw new Error('Unknown Error')
}
login()
Executing this code returns me UnhandledPromiseRejectionWarning, but I realized that if I put a try catch inside the catch of login functionn, this warning disappears
} catch (error) {
try {
handleLoginError(error)
} catch (err) {
console.log('Ooppss', err)
}
When I do this my code enter in the nested catch and the "err" value is the value of the handleLoginError(error)
How can I do the same without executing a try catch inside the catch?

It seems you need to call login as follows:
try {
await login();
}
catch(err) {
// handle here the error
}

Related

How does error handling work for async map inside an async function?

I have successfully created a function that creates folders according to a directory.
However, when I have tried to convert the for of into a map() method using Promise.all(), the error was not handled the same.
import { readdir, mkdir } from 'fs/promises';
const copyUsingFor = async (target) => {
try {
const dir = await readdir(`./test`, { withFileTypes: true });
for (const item of dir) {
if (item.isDirectory()) {
try {
await mkdir(`./${target}`);
}
catch (err) {
throw err;
}
}
}
}
catch (err) {
console.log(`desired err handling`);
throw err;
}
}
const copyUsingMap = async (target) => {
try {
const dir = await readdir(`./test`, { withFileTypes: true });
Promise.all(
dir.map(async item => {
if (item.isDirectory()) {
try {
await mkdir(`./${target}`);
}
catch (err) {
throw err;
}
}
})
)
}
catch (err) {
throw err;
}
}
copyUsingFor(`../`).catch(err => console.log(`An error occurred: ${err}`)) // <- Works.
copyUsingMap(`../`).catch(err => console.log(`An error occurred: ${err}`)) // <- Gives "triggerUncaughtException".
I am guessing it is because I have an async inside another, but could not figure out why it does not works the same.
Thanks!
You are missing the await in front of Promise.all, that's all. Because of this, what happens inside the Promise.all is detached from the rest of your program flow.
Side note: catch (err) { throw err } is a no-op. You can get rid of the whole try/catch if you don't do anything other than rethrowing the error in it. It feels a bit like wrapping stuff in a call to a function x => x.

Catch promise rejection in nested function

I have this repro: https://codesandbox.io/s/jolly-bogdan-k6ii4?file=/src/index.ts
code:
const wait = (timeoutMs: number) => {
let timeoutHandle: number | undefined;
const promise = new Promise((_resolve, reject) => {
timeoutHandle = setTimeout(() => {
reject(`wait timed out after ${timeoutMs} ms`);
}, timeoutMs);
});
return {
promise,
cancel: (): void => clearTimeout(timeoutHandle)
};
};
const waitBy = (timeoutMs: number) => {
const res = wait(timeoutMs);
return res;
};
const main = async () => {
try {
const { promise, cancel } = waitBy(3000);
} catch (error) {
console.log("failed on timeout");
}
// try {
// await promise;
// } catch (error) {
// console.log("timed out");
// }
};
main();
When this is ran in Node.js, the reject will throw after 3s, and blow up the whole process with an "unhandledRejection Error" - where can one catch this error to avoid an unhandledRejection Error, but allow it to propagate up to the catch inside the main function?
The problem is that you're not waiting for the promise to resolve before moving forward and the error is thrown then outside of the try block.
const main = async () => {
try {
const { promise, cancel } = waitBy(3000);
await promise // new code
} catch (error) {
console.log("failed on timeout");
}
// try {
// await promise;
// } catch (error) {
// console.log("timed out");
// }
};

logging errors in async functions

I have this code:
async function getURL() {
try {
await fetch("http://www.blah.com");
return 0;
} catch (err) {
return err;
}
}
getURL().then( result => {
if (result === 0) console.log("success");
else console.log(result);
});
The fetch will fail and the error is logged to the console. How do I rework the code so it uses async and try/catch everywhere? That is, I'm looking to avoid doing getURL().then for the sake of consistency.
EDIT:
For those downvoting me, await getURL() won't work as it's invalid syntax.
EDIT2:
Tried this but it didn't catch the error:
async function getURL() {
return await fetch("http://www.blah.com");
}
let result = async function() {return await getURL();}
try {
result();
} catch (e) {
console.log(e);
}
You can wrap your whole code inside an instantly executed async function like this:
// service.js
async function getURL() {
return await fetch("http://www.blah.com");
}
// your.module.js
(async function() {
// do things...
try {
let result = await getURL();
} catch (e) {
console.log(e);
}
// do things...
res.send({});
});
Every time you need to catch an error from promise, either using new Promise, async-await or generator you need to use .then() or you can do something like this another async-await.
async function getURL() {
try {
await fetch("http://www.blah.com");
return 0; // EDIT: just returning value which is success
} catch (err) {
return err; // EDIT: returning value not rejecting a promise
}
}
async function main () {
try {
let result = await getURL();
if (result === 0) console.log("success");
console.log(result); // EDIT: error will be print.
}
catch (err) { // EDIT: getURL() never rejects so always success.
console.log(err);
}
});
main();
This situation doesn't really occurs as while our main function in server-side or client-side are async and handling this for us.
Like using express:
app.post('/api', async (req, res) => {
try {
let result = await getURL();
res.send(async);
}
catch(err) {
res.send(err);
}
});
EDIT: asyn-await doesn't reject or resolve a call, just return a value. thus must be used carefully.
function fetch(url) {
return new Promise( (resolve, reject) => {
let x = Math.floor(Math.random() * Math.floor(9) + 1);
// 50-50 resolve or reject
if(x%2===0) return resolve(false); //resolve with `false` statement
reject(true); // reject with `true` still a reject
});
}
async function getURL() {
try {
await fetch("http://www.blah.com");
return 0; // if fetch resolve
} catch (err) { //only if fetch reject
return err;
}
}
async function main () {
try {
let result = getURL();
if (result === 0) console.log("success"); //getURL never reject any call
console.log(result);
}
catch (err) { // getURL doesnt reject
console.log(err);
}
};
main();
I realize now async functions always return a promise. Even if you throw an error it still gets wrapped up into a promise. Therefore using try/catch won't help. This is how I ended up writing the code:
async function getURL() {
return await fetch("http://fake");
}
getURL().then( () => console.log("success")).catch( (e) => console.log(e));

Catching Uncaught Error in my async await function

I am trying to use async/await keywords with Redis and NodeJS. I can catch simple errors but I can't catch exceptions coming from getKeys function. Following mocha test fails. My catch block is also not called. I am using NodeJS v9.3.0 and bluebird v3.5.1 and redis 2.8.0
const redis = require("redis");
const bluebird = require("bluebird");
const assert = require('assert');
bluebird.promisifyAll(redis.RedisClient.prototype);
class RedisManager {
constructor(host) {
this.client = redis.createClient({'host':host});
}
async getKeys(key) {
let result = await this.client.hgetallAsync(key);
return result;
}
async simple(key) {
throw Error('Simple Error: ' + key)
}
}
describe('Redis Manager Test:', function() {
it('catches simple errors',function (done) {
let manager = new RedisManager('BOGUSHOST');
let key = 'testKey';
manager.simple(key)
.then(function (value) {
console.log('Value: ' + value);
done(value,null)
})
.catch(function (err) {
if (err = Error('Simple Error: ' + key)) {
done(null);
} else {
done(err);
}
})
});
it('catches Redis errors',function(done) {
let manager = new RedisManager('BOGUSHOST');
manager.getKeys('Some')
.then(function(value) {
console.log('Value: ' + value);
done(value,null)
})
.catch(function (err) {
console.log('Caught Error: ' + err);
done(err,null);
})
})
});
You should use try/catch block to handle Uncaught error rejection when using async/await.
async getKeys(key) {
let result = await this.client.hgetallAsync(key);
try {
return result;
}
catch (err) {
return err;
}
}

Proper error handling using async/await in Node.js

I have the following code in my Node.js express app:
router.route('/user')
.post(async function(req, res) {
if(req.body.password === req.body.passwordConfirm) {
try {
var response = await userManager.addUser(req.body);
res.status(201).send();
} catch(err) {
logger.error('POST /user failed with error: '+err);
res.status(500).send({err:"something went wrong.."});
}
} else {
res.status(400).send({err:'passwords do not match'});
}
})
and userManager:
var userManager = function() {
this.addUser = async function(userobject) {
userobject.password_hash = await genHash(userobject.password_hash);
var user = new User(userobject);
return await user.save();
};
};
module.exports = userManager;
My question is: Will the try catch block in the route catch all errors thrown in addUser or will it only catch the ones that are thrown by user.save(), since that is the one that gets returned?
The answer is yes, it will catch all the errors inside try block and in all internal function calls.
async/await is just syntax sugar for promises. Thus if something is possible using promises then it is also possible using async/await.
For example both of the following code snippets are equivalent:
Using promises:
function bar() {
return Promise.reject(new Error('Uh oh!'));
}
function foo() {
return bar();
}
function main() {
return foo().catch(e => {
console.error(`Something went wrong: ${e.message}`);
});
}
main();
Using async/await:
async function bar() {
throw new Error('Uh oh!');
}
async function foo() {
await bar();
}
async function main() {
try {
await foo();
}
catch(e) {
console.error(`Something went wrong: ${e.message}`);
}
}
main();
In fact your code will not work since you don't use await on userManager.addUser.
It also forces you to use async on the parent function and that may break things up. Check express documentation (or just try if it works).
router.route('/user')
.post(async function(req, res) {
if(req.body.password === req.body.passwordConfirm) {
try {
var response = await userManager.addUser(req.body);
res.status(201).send();
} catch(err) {
logger.error('POST /user failed with error: '+err);
res.status(500).send({err:"something went wrong.."});
}
} else {
res.status(400).send({err:'passwords do not match'});
}
})

Resources