Where is the unhandled promise rejection? How can I avoid it? - javascript

Working with Node and mssql to pull queries for five different databases to de-dupe against each other and merge into a more unified schema.
My process follows this algorithm:
create a shared pool by calling this function:
const getPoolConnection = async () => {
try {
let pool = await mssql.connect(`mssql://${username}:${password}#${server}/`);
return pool;
} catch (err) {
console.error(err);
}
};
This function creates the pool and returns it to the calling function. username, password, and server are imported and scoped to this file.
Then we query each database and assign the result to a property on an object. This is accomplished via a forEach loop:
lists.forEach(list => {
fullData[list] = db.queryDatabase(pool, customers[list].query).catch(err => console.error(err));
})
which calls this function:
const queryDatabase = async (pool, query) => {
try {
let result = await pool.request().query(query);
// console.log(result);
return result.recordset, pool;
} catch (err) {
console.error(err);
}
};
now in order to keep post-processing from occuring before all database calls return data, I've wrapped the entire set of calls in a Promise.all() call in the main index.js file. This is the calling funciton:
const { customers } = require('./query');
const util = require('./util');
const db = require('./db');
fullData = {};
(async () => {
let pool = await db.getPoolConnection();
let lists = Object.keys(customers);
Promise.all(
lists.forEach(list => {
fullData[list] = db.queryDatabase(pool, customers[list].query).catch(err => console.error(err));
})
)
.then(results, pool => {
console.dir(results);
db.closePoolConnection(pool);
})
.catch(err => console.error(err));
})();
What I don't understand is this error that occurs when attempting to debug the application:
(node:18908) UnhandledPromiseRejectionWarning: TypeError: Cannot read
property 'Symbol(Symbol.iterator)' of undefined warning.js:18
at Function.all ()
at c:\Users\rutherfordc\Documents\GitHub\migration-plus\index.js:10:11
at
at process._tickCallback (internal/process/next_tick.js:188:7) (node:18908) 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) warning.js:18
(node:18908) [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. warning.js:18 (node:18908) UnhandledPromiseRejectionWarning:
ReferenceError: results is not defined warning.js:18
at c:\Users\rutherfordc\Documents\GitHub\migration-plus\index.js:15:11
at
at process._tickCallback (internal/process/next_tick.js:188:7) (node:18908) 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: 2)

Promise.all() needs an array. So you could do something like this:
fullData = [];
(async () => {
let pool = await db.getPoolConnection();
let lists = Object.keys(customers);
lists.forEach(list => {
fullData.push(db.queryDatabase(pool, customers[list].query).catch(err => console.error(err));
}));
Promise.all(fullData)
.then((results, pool) => {
console.dir(results);
db.closePoolConnection(pool);
})
.catch(err => console.error(err));
})();
Update:
Also as J. Pichardo suggested in his answer, in case of multiple parameters, the parameters should be enclosed in parentheses.
Documentation

The error is non-logical but syntactical, the following lines in the main function
.then(results, pool => {
console.dir(results);
db.closePoolConnection(pool);
})
The arguments of the arrow function should be surrounded by parentheses, like:
.then((results, pool) => {
console.dir(results);
db.closePoolConnection(pool);
})
ReferenceError: results is not defined
So, the then is looking for a results variable and since it is an async function when it crashes it will be a UnhandledPromiseRejection.
Update:
As the other answer says Promise.all receives either multiple promises or an array of promises, so you could do something like:
var fullData = lists.map(list => db.queryDatabase(pool, customers[list].query).catch(err => console.error(err)));
Promise.all(fullData).then(...)

Related

Typescript: issue with async await promise.all looping through all results

Having an issue with this result set due to it being type unknown. I've tried several different things but keep getting the same error and not sure what to do. Thanks for any help!
Here is the error message -
TypeError: Cannot read property 'props' of undefined
at C:\TS\mytask\src\helloworld.js:153:47
at step (C:\TS\mytask\src\helloworld.js:33:23)
at Object.next (C:\TS\mytask\src\helloworld.js:14:53)
at C:\TS\mytask\src\helloworld.js:8:71
at new Promise (<anonymous>)
at __awaiter (C:\TS\mytask\src\helloworld.js:4:12)
at C:\TS\mytask\src\helloworld.js:144:60
at new Promise (<anonymous>)
at searchUsers (C:\TS\mytask\src\helloworld.js:144:12)
at Object.<anonymous> (C:\TS\mytask\src\helloworld.js:173:13)
Promise { <rejected> [] }
(node:37216) UnhandledPromiseRejectionWarning: [object Array]
(Use `node --trace-warnings ...` to show where the warning was created)
(node:37216) 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(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:37216) [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.
Code -
function searchUsers(filterText: string): IPersonaProps[] | Promise<IPersonaProps[]> {
return new Promise(async (resolve: any, reject: any) => {
let People: IPersonaProps[] = [];
try {
const tempPeople = await this.props.context.webAPI.retrieveMultipleRecords("systemuser?$select=fullname,internalemailaddress,systemuserid");
await Promise.all(tempPeople.entities.map((entity: any ) =>{
People.push({ "text": entity.fullname, "secondaryText": entity.internalemailaddress, "id" : entity.systemuserid }); //change fieldname if values are different
}));
resolve(People);
}
catch (err) {
console.log(err);
reject(People);
}
});
}
Currently this works fine for 1 result, but when I try to get back a collection of results and loop through them to push to the People array, I always keep getting the same error.
Thanks again!
It looks like this is a member function of a class you have declared but have not initialized hence this being undefined. To confirm please add the code of how you are using your class...
private _searchUsers(filterText: string): IPersonaProps[] | Promise<IPersonaProps[]> {
return new Promise(async (resolve: any, reject: any) => {
let People: IPersonaProps[] = [];
// This is a reference to a class
const tempPeople = await this.props.context.webAPI.retrieveMultipleRecords("systemuser?$select=fullname,internalemailaddress,systemuserid");
// Need to make the callback function async so that it becomes an array of promises
await Promise.all(tempPeople.entities.map(async (entity: any ) => {
People.push({ "text": entity.fullname, "secondaryText": entity.internalemailaddress, "id" : entity.systemuserid }); //change fieldname if values are different
}));
resolve(People);
}
catch (err) {
console.log(err);
reject(People);
}
});
}
I found the issue. Here's how I was able to get it working. Thanks for the help!
private _searchUsers(filterText: string): IPersonaProps[] | Promise<IPersonaProps[]> {
return new Promise(async (resolve: any, reject: any) => {
let People: IPersonaProps[] = [];
const config = new WebApiConfig("9.1");
const options: string = "?$select=fullname,internalemailaddress,systemuserid";
retrieveMultiple(config, "systemusers", options)
.then(
(results) => {
const People: IPersonaProps[] = [];
for (const record of results.value) {
People.push({ "text": record.fullname, "secondaryText": record.internalemailaddress, "id" : record.systemuserid });
resolve(People);
}
},
(error) => {
reject(People);
console.log(error);
}
);
});
};

How to pass read data from await readFile to writeFile in fs module of node.js?

In this code, file is being opened and read successfully.
var objFs = require('fs')
async function openFile() {
await objFs.open('new.js', 'r', (argError, argFD) => {
if (argError)
throw -1
else
console.log("File opened!")
})
// This object is the promise.
const objReadResult = await objFs.readFile('new.js', (argError, argData) => {
if (argError)
throw 2
else
console.log('File read!')
})
await objFs.writeFile('new.js', (argError, objReadResult) => {
try
{
if( argError )
throw argError
else
console.log("File written")
}
catch( arg )
{
console.log(arg)
}
})
}
openFile()
What is the way to extract the data from await of readFile and pass it to writeFile?
The way I have written the writeFile function is producing the following error:
(node:21737) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_CALLBACK]: Callback must be a function. Received undefined
at maybeCallback (fs.js:145:9)
at Object.writeFile (fs.js:1332:14)
at openFile (/home/sulakshana/Documents/nodejs/programs/async_await.js:29:14)
(node:21737) 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(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:21737) [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.
File opened!
File read!
Few issues I can see:
there is a mix of syntaxes - async/await while also providing callbacks to the fs calls;
no need to call fs.open before fs.readFile;
there are no data to be written in fs.writeFile [docs];
there should be await-ing at the end;
and the final (the actual error reported) - there should be try...catch block to catch and react to any errors that occur.
Example implementation:
const fs = require('fs').promises;
async function openFile() {
const objReadResult = await fs.readFile('new.js');
console.log('File read!');
await fs.writeFile('new.js', /* PROVIDE DATA TO WRITE */);
console.log('File written');
}
(async () => {
try {
await openFile();
console.log('Program is done');
} catch (err) {
console.error(err);
}
})();

Async/await call returns undefined when used in conjunction with promises

I am having an issue where an Async call to my database returns undefined.
The function "findOne" retrieves one row from the database, but the .then(... function is executing before the row is returned.
I've tried changing what I return in the DB function findOne as well as adding an 'await' on the function call. I've also tried using Promise.resolve(db.findOne({requestbody}).then(... but no luck with that either.
Here is the db.findOne method
const findOne = async (req) => {
const { teamId, channelId, isClosed } = req;
return db.query('SELECT * FROM polls where team_id= $1 and channel_id =$2 and is_closed = $3 LIMIT 1',
[teamId, channelId, isClosed],
(error, results) => {
if (error) {
throw error;
}
console.log("\nDBRes: \n", results.rows[0])
return results.rows[0];
}
);
};
And here is where I call the function
app.post('/', (req, res) => {
const slashCommand = req.body.command;
switch (slashCommand) {
//...
//... Some other code
//...
case 'results':
db.findOne({
teamId: requestBody.team_id,
channelId: requestBody.channel_id,
isClosed: false,
})
.then((row) => {
console.log(row);
const poll = pollFuncs.getPollfromResultRow(row);
const displayText = pollFuncs.getFormattedPollResults(poll);
res.status(200).send({
text: displayText,
});
});
break;
//... The rest of the function
Here are the logs I am getting.
Note* I am currently logging the "row" object both inside the .then(...) function and inside the pollFuncs.getPollfromResultRow(row); function
Bot is listening on port 3000
undefined
undefined
(node:14000) UnhandledPromiseRejectionWarning: TypeError: Cannot destructure property `id` of 'undefined' or 'null'.
at Object.getPollfromResultRow (C:\Users\ztb0504\Documents\Projects\Node\werewolfmod\pollFunctions.js:97:125)
at db.findOne.then (C:\Users\ztb0504\Documents\Projects\Node\werewolfmod\index.js:59:56)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:14000) 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:14000) [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.
DBRes:
{ id: '22',
poll_title: 'This is a new Pollstgresql',
//The rest of the expected data....
}
I'd appreciate any guidance on how to get this to return data as expected.
Thank you!
You're mixing plain callbacks and promises and it is causing you problems. It will be a lot easier if you don't do that.
If you pass a plain callback to db.query(), then it won't return a promise. In fact, it will return nothing (undefined). So, when you do return db.query(), all you're doing is returning undefined.
Change to this:
const findOne = async (req) => {
const { teamId, channelId, isClosed } = req;
return db.query('SELECT * FROM polls where team_id= $1 and channel_id =$2 and is_closed = $3 LIMIT 1',
[teamId, channelId, isClosed]).then(results) => {
console.log("\nDBRes: \n", results.rows[0])
return results.rows[0];
});
};
The, you also need error handling in your request handler if there are any errors in the query. Promise handling should nearly always have a .catch() somewhere to handle errors:
case 'results':
db.findOne({
teamId: requestBody.team_id,
channelId: requestBody.channel_id,
isClosed: false,
}).then((row) => {
console.log(row);
const poll = pollFuncs.getPollfromResultRow(row);
const displayText = pollFuncs.getFormattedPollResults(poll);
res.status(200).send({
text: displayText,
});
}).catch(err => {
console.log(err);
res.sendStatus(500);
});
break;

Unhandled promise rejection. This error originated either by throwing inside of an async function - NodeJS

I'm very new with NodeJS. I'm trying to create a simple server that has a connection to my mongoDB Atlas database but when I run my server I get this error:
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:8825) [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.
Seems to be a common problem based on what I googled, I added the try/catch but it still isn't working.
'use strict';
//const AWS = require('aws-sdk');
const express = require('express');
const mongoose = require('mongoose');
const uuidv4 = require('uuid/v4');
//exports.handler = (event, context, callback) => {
mongoose.connect(
'mongodb+srv://xxxx:xxxx#cluster0-us8bq.mongodb.net/test?retryWrites=true',
{
useNewUrlParser: true
}
),
() => {
try {
//something
} catch (error) {
console.error(error);
}
};
const connection = mongoose.connection;
connection.once('open', () => {
console.log('🖥 Connection to DB was succesful');
});
const app = express();
app.listen({ port: 4800 }, () =>
console.log(`🚀 Server ready at http://localhost:4800`)
);
Mongoose connect returns promise, and most probably there is an error when it attempts to connect: I would suggest using the async function, to handle DB connection. Here is what I use currently.
const config = require('config').db; // Your DB configuration
const combineDbURI = () => {
return `${config.base}${config.host}:${config.port}/${config.name}`;
};
// Connecting to the database
const connect = async function () {
const uri = combineDbURI(); // Will return DB URI
console.log(`Connecting to DB - uri: ${uri}`);
return mongoose.connect(uri, {useNewUrlParser: true});
};
And then call it within an async function using await:
(async () => {
try {
const connected = await connect();
} catch(e) {
console.log('Error happend while connecting to the DB: ', e.message)
}
})();
Or you can call without await using promise API:
connect().then(() => {
console.log('handle success here');
}).catch((e) => {
console.log('handle error here: ', e.message)
})
Besides, using try catch when using callbacks does not make sense, when you don't have promises, you should use error callbacks to catch errors.
So to answer your question (as others mentioned in the comments):
As connect function returns a promise, you should use catch callback to catch the promise rejection. Otherwise, it will throw Unhandled Promise Rejection.
I hope this will help.
UnhandledPromiseRejectionWarning means that promises should have .catch() like
mongoose.connect(...).catch(err => console.log(err))

I cant handle promise rejections

I have a service that analyses websites, compresses their sources like CSS Documents, Images etc. I have 2 functions, one is Socket.IO socket.on() method with async callback function. Another is main function for service.
socket.on('run', async options => {
debug(`${options.target} Adresine Bir Kullanıcı İstek Yaptı!`);
let user = null;
console.log(options);
if(options.token) {
user = await User.findById(jwt.verify(options.token, config.get('jwtPrivateKey'))._id);
options.userId = user._id.toString();
} else if(options.visitor) {
user = await Visitor.findById(options.visitor._id);
if(user.report) {
return socket.emit('error', new Error('You have exceeded your report limit'));
} else {
options.userId = user._id.toString();
}
}
if(options.userId) {
let userType = await UserType.find({ name: user.type });
if(userType.length > 0 && ((user.type == 'Visitor' && user.report == undefined) || (user.reports.length < userType[0].rights.reportsLimit.limit || userType[0].rights.reportsLimit.unlimited))) {
options.rights = userType[0].rights;
let { error, data } = await wrapper(runService(options.target, options, socket));
if(error) {
console.log('Here', error);
return socket.emit('error', error);
}
.
.
.
}
.
.
.
}
});
In the above function,
let { error, data } = await wrapper(runService(options.target, options, socket));
if(error) {
console.log('Here', error);
return socket.emit('error', error);
}
This part is important, because I call my main async service function runService with my async function wrapper function that is named wrapper. The wrapper function is this;
const wrapper = promise => (
promise
.then(data => ({ data, error: null }))
.catch(error => ({ error, data: null }))
);
In my main async service function, I only throw an error;
async function runService(target, options, socket) {
throw new Error('any error');
}
But the expected output is much different from actual output. Here is the output of this code;
Here Error: any error
at startService (C:\Projeler\OpDetect\Background-Service\lib\app.js:404:11)
at Socket.socket.on (C:\Projeler\OpDetect\Background-Service\app.js:73:57)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:16600) UnhandledPromiseRejectionWarning: Error: any error
at startService (C:\Projeler\OpDetect\Background-Service\lib\app.js:404:11)
at Socket.socket.on (C:\Projeler\OpDetect\Background-Service\app.js:73:57)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:16600) 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: 2)
(node:16600) [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.
My expectation about the output is, like this;
Here Error: any error
at startService (C:\Projeler\OpDetect\Background-Service\lib\app.js:404:11)
at Socket.socket.on (C:\Projeler\OpDetect\Background-Service\app.js:73:57)
at process._tickCallback (internal/process/next_tick.js:68:7)
Because I already handled the promise rejection with my wrapper function and catched the rejection, Why is 2 more UnhandledPromiseRejectionWarning errors on rejection?
Also, the line,
return socket.emit('error', error);
is not calling for no reason. It should have been called when the if statement truthy. Why is not this socket.emit function called?
As best practice use try {} catch(){} with async/await.
For ex.
userUtils.signUp = async (userName) => {
try {
const callFunction = await userUtils.checkExistancy(userName);
if (!callFunction.isExist) {
...
} else {
...
}
} catch (err) {
console.log(err);
throw err;
}
};
in your case it will be like
socket.on('run', async options => {
try {
user = await User.findById(jwt.verify(options.token, config.get('jwtPrivateKey'))._id);
options.userId = user._id.toString();
return true;
} catch (err) {
throw err;
}});

Categories

Resources