Unhandled Promise Rejection with a .catch() [duplicate] - javascript

This question already has answers here:
why settimeout not delay the function execution?
(2 answers)
Closed 5 years ago.
I'm having trouble debugging my first Javascript tool which uses promises. I feel like I am using the .catch() method correctly, as it matches up with other StackOverflow answers to similar questions that have been asked, however I'd still receiving an UnhandledPromiseRejectionWarning for uncaught promises.
My program fetches a list of objects from an S3 and then logs them to console.
Here is the promise chain
s3Helper.setCredentials(program.profile)
.then(s3Helper.findObjects([], null))
.then(data => console.log(data))
.catch(err => utl.error(err));
And here are the two promises
function findObjects (keyArray, token) {
return new Promise((resolve, reject) => {
var S3 = new AWS.S3({apiVersion: '2006-03-01'});
var params = {
Bucket: program.bucket,
Prefix: program.prefix,
Delimiter: program.recursive ? '' : '/',
ContinuationToken: token
};
S3.listObjectsV2(params, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
function setCredentials (profile) {
// Sets AWS credentials, and rejects if the profile is not found
return new Promise((resolve, reject) => {
AWS.config.credentials = new AWS.SharedIniFileCredentials({profile: profile});
AWS.config.credentials.refresh((err, data) => {
if (err) {
reject(err);
} else if (AWS.config.credentials.accessKeyId) {
resolve();
} else if (AWS.config.credentials.roleArn) {
resolve();
} else {
var error = {
message: `Given profile '${program.profile}' does not exist`
};
reject(error);
}
});
});
}
Sorry if my style or code is bad, I'm still getting used to Javascript!

Your promise chain should look like this:
s3Helper.setCredentials(program.profile)
.then(() => s3Helper.findObjects([], null))
.then(data => console.log(data))
.catch(err => util.error(err));
Note the function: () => ... on the second line
Then .then() method takes a function as it's argument. So you must pass it a function.
Therefore, .then(s3Helper.findObjects([], null)) would only work if s3Helper.findObjects([], null) returns a function. But based on you definition of s3Helper.findObjects([], null), it doesn't. So you need to update your .then() method to .then(() => s3Helper.findObjects([], null)).

Related

The promise get resolved in undefined [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
I'm trying to understand how promises and the async-await stuff work and I built the following code to get the list of connected devices on the computer but it returns 'undefined'.
var iosDevice = require("node-ios-device");
const the_action = () => {
iosDevice.devices(function (err, devices) {
if (err) {
console.error("Error!", err);
} else {
return devices;
}
});
}
const create_promise = () => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(the_action()), 100);
});
};
const the_devices = create_promise();
const resolvePromise = (promise) => {
promise
.then((result) => console.log(result))
.catch((error) => HTMLFormControlsCollection.log(error));
};
resolvePromise(the_devices);
I'm running the above script from terminal using node:
$> node the_script.js
What am I'm doing wrong or missing?
Thank you in advance
the_action isn't returning anything. Your return statement simply returns from the iosDevice.devices callback - but the containing function doesn't return anything. That's where your problem lies. If you get the_action to return something, it will bubble up through your promise resolution and end up getting console.logged

Should I use Promises when using Axios? [duplicate]

This question already has answers here:
What is the explicit promise construction antipattern and how do I avoid it?
(3 answers)
Closed 3 years ago.
Axios is described as Promise-based, so is there a need for returning a new Promise when using Axios to query for data?
app.get('/api/nearbyRecommendations', async (req, res) => {
if(!req.query) return res.send({ error: 'Please enable location to get recommendations.' })
try {
const { longitude, latitude } = req.query
const locationName = await location.getLocationName(longitude, latitude)
res.send(locationName)
} catch (error) {
res.send(error)
}
})
I am making a GET request to the MapBox API, but I do not seem to ever get any errors despite setting up the catch block for my Axios request, even if I throw a new Error in the .then() block.
const getLocationName = async (latitude, longitude) => {
return new Promise((resolve, reject) => {
axios.get(`https://api.mapbox.com/geocoding/v5/mapbox.places/${longitude},${latitude}.json?access_token=${darkSkyAPIKey}`, {json: true})
.then(response => {
if(!response.data) return reject({ error: 'No location found.' })
resolve(response.data)
}).catch(error => {
reject(error)
})
})
}
If possible, do help and point out anything that may be altered to follow best practices.
You can just return the promise immeditately without using an async function:
const getLocationName = (latitude, longitude) => {
return axios.get(`https://api.mapbox.com/geocoding/v5/mapbox.places/${longitude},${latitude}.json?access_token=${darkSkyAPIKey}`, {json: true})
.then(response => {
if(!response.data)
throw Error('No location found.')
return response.data;
}).catch(error => {
console.log(error);
throw error;
})
}
Axios.get already returns a promise to you. If you also define the function as async that means that the returned promise will be wrapped in a promise again. So in your example you were triple wrapping the response in a promise. If you replace it with the getLocationName function with a regular function, usage in the first code snippet will remain exactly the same.

How to handle an array of Promises then/catch

I don't know to to resolve this situation using JS promises.
Imagine I have some articles and I want to send a patch request to update them. I send one request per article. If the request of one article success then I update that article, but if the request fails, then I update the article differently. Also I want to show a message to the user informing if all the articles have been updated correctly or not.
This is not my real scenario and this may be a weird example. But it's what I want to accomplish in my React app.
Here is what I'm trying to do right now:
const saveArticles = articles => {
const promises = [];
articles.forEach(article => {
const promise = axios
.patch('/articles', article)
.then(() => updateArticleUi(article))
.catch(() => updateArticleUiWithError(article));
promises.push(promise);
});
Promise.all(promises)
.then(() => tellTheUserThereWasNoErrors())
.catch(() => tellTheUserThereWasSomeErrors());
};
This isn't working because the Promise.all is always executing the then callback, weather all promises succeed or not.
Thanks!
Your updateArticleUi and updateArticleUiWithErrors should have the respective return values so that you can distinguish whether there was an error or not when looking at the array of results:
function updateArticleUi(article) {
…
return {success: true};
}
function updateArticleUiWithError(article, error) {
…
return {success: false};
}
function saveArticles(articles) {
const promises = articles.map(article => {
return axios.patch('/articles', article).then(() =>
updateArticleUi(article)
, err =>
updateArticleUiWithError(article, err)
);
});
return Promise.all(promises).then(results =>
if (results.every(res => res.success)) {
tellTheUserThereWasNoErrors();
} else {
tellTheUserThereWasSomeErrors();
}
});
}
This works:
function axiosPatchRequest(url,data) {
return new Promise(function (resolve, reject) {
if (data) {
resolve(url);
} else {
reject('DATA_NOT_FOUND');
}
})
}
function updateArticleUi(data,article) {
return new Promise(function (resolve, reject) {
resolve({type:"updateArticleUi ",data,article});
})
}
function updateArticleUiWithError(data,article) {
return new Promise(function (resolve, reject) {
reject({type:"updateArticleUiWithError ",data,article});
})
}
function tellTheUserThereWasNoErrors(data){
console.log("tellTheUserThereWasNoErrors",data);
}
function tellTheUserThereWasSomeErrors(error){
console.log("tellTheUserThereWasSomeErrors",error);
}
const execute = (articles)=>{
const promises = [];
articles.forEach(article => {
const promise = axiosPatchRequest('/articles', article)
.then((data) => {
return updateArticleUi(data,article);
})
.catch((error) => {
return updateArticleUiWithError(error,article);
});
promises.push(promise);
});
Promise.all(promises)
.then((data) => tellTheUserThereWasNoErrors(data))
.catch((error) => tellTheUserThereWasSomeErrors(error));
};
execute(["one","","three"]);
execute(["one","two","three"]);
Promise.all will always call then because the promise you add to promises is already resolved one with either then or catch attached above
if you want to see catch to happen in .all chain just throw some exeption in updateArticleUiWithErro function
The problem is that you are catching the error thrown by
const promise = axios
.patch('/articles', article)
.then(() => updateArticleUi(article))
.catch(() => updateArticleUiWithError(article));
you should either throw a new error in the axios catch() or let the error bubble up by removing the catch from the axios call.

Promise chain with an asynchronous operation not executing in order

I have found other people asking about this topic but I haven't been able to get my promise chain to execute in order.
Here is a basic reproduction of what is happening:
function firstMethod(){
dbHelper.executeQuery(queryParameters).then(result => {
if (result === whatIAmExpecting) {
return dbHelper.doDbOperation(secondQueryParameters)}
else {
throw new Error('An error occurred')
}})
.then(doFinalOperation())
.catch(error => {
})
}
In the above code doFinalOperation() is called before the then function after executeQuery() is called.
Here is the implementation of executeQuery():
function executeQuery(parameter) {
return new Promise((resolve, reject) => {
const queryToExecute = `SELECT * FROM parameter`
return mySqlConnection.query(queryToExecute).then((result) => {
resolve(result)
}).catch(error => {
reject(error)
})
})
And here is the implementation of of the mySqlConnection.query method:
function query(queryString){
return new Promise((resolve, reject) =>
{
initConnection()
connection.connect()
require('bluebird').promisifyAll(connection)
return connection.queryAsync(queryString).then(function(results) {
connection.end();
resolve(results)
}).catch(error => {
reject(error)
})
})
It seems like I have incorrectly implemented the executeQuery() method. The database operation in the mySqlConnection.query is asychronous and I can see that's where the chain of promises stops happening in the expected order.
My question in a nutshell: How do I make the my chain of promises execute in order, and how I do stop a then() method from being executed before the previous Promise has called resolve() or reject()?
Thanks in advance.
then expects a function, but you have accidentally executed it, instead of passing it. Change:
then(doFinalOperation())
with:
then(doFinalOperation)
Now it will be the promise implementation that invokes it (at the proper time), not "you".
If your function needs arguments to be passed, then you can either
(1) Use bind:
then(doFinalOperation.bind(null, parameterOne, parameterTwo, parameterThree))
(2) Use a function expression
then(_ => doFinalOperation(parameterOne, parameterTwo, parameterThree))
Both your .then() methods get called on the first async operation...
Should be something like this:
function firstMethod(){
dbHelper.executeQuery(queryParameters).then(expectedResult => {
if (expectedResult === whatIAmExpecting) {
return dbHelper.doDbOperation(secondQueryParameters)}
.then(doFinalOperation())
.catch(error => {
};
}
else {
throw new Error('An error occurred')
}})
.catch(error => {
});
}

How to use callback or promises in node js? [duplicate]

This question already has answers here:
How do I convert an existing callback API to promises?
(24 answers)
Closed 6 years ago.
Hello I am new to promises and callbacks in node js
I am doing something to fetch users list using another function using callbacks but getting fail.
somewhere I found to use promises. but never used promises.
can anyone help me with code?
send_noti('12', function(res){
console.log(res);
});
function send_noti(value, callback){
connection.query(" SELECT * from users ", function( err, res ){
callback( res );
});
}
You're looking for something like this:
function sendNotiAsync(value) {
return new Promise((resolve, reject) => // Promise constructor
connection.query("SELECT * from users", (err, data) => // Perform the action
err ? reject(err) : resolve(data))); // If error exists, reject, else resolve
}
And use it like this:
sendNotiAsync(someValue)
.then(data => {
// Work with data here, for example
console.log(data);
})
.catch(err => {
// Handle errors here
console.error(err);
});
In node callbacks of async functions should always have the signature function(err, result /*,...*/)
Your example should look like:
send_noti('12', function(err, res) {
if( !err ) {
console.log(res);
}
});
function send_noti(value, callback) {
connection.query(" SELECT * from users ", callback );
}
Beside that your example does not use Promises. With Promises it would look like this:
send_noti('12')
.then(function(res) {
console.dir(res)
})
.catch(function(err) {
console.dir(err)
})
function send_noti(value, callback) {
return new Promise(function(resolve, reject) {
try {
connection.query(" SELECT * from users ", function(err, res) {
if (err) {
reject(err);
} else {
resolve(res);
}
});
} catch (err) {
reject(err);
}
})
}

Categories

Resources