I just started out learning Node.js / Express and I still have difficulties with the Asynch functions. I made some functions to interact with a postgresql database (with some tutorials), and selecting rows from data is going fine but for some reason something is going from with deleting the rows. Here is an example of a function that is going well:
const getPlayers = () => {
return new Promise(function(resolve, reject) {
pool.query('SELECT * FROM Players ORDER BY p_id ASC', (error, results) => {
if (error) {
reject(error)
}
resolve(results.rows);
})
})
}
Now the following function is not going well. Console.log(id) gives the right number, but it seems that id is undefined when executing the query and I suspect that it has to do with Asynch/synch. Now Asynch is new for me, so I am also not an expert on what is going wrong.
Here is the function that is nog going good:
const deletePlayer = (id) => {
return new Promise(function(resolve, reject) {
pool.query('DELETE FROM Players WHERE player_id = ?' , [id], (error,results) => {
if (error) {
reject(error)
}
resolve(`Player deleted with ID: ${id}`)
})
})
}
The function call:
app.delete('/laProjects/:id', (req, res) => {
players_model.deletePlayers(req.params.id)
.then(response => {
res.status(200).send(response);
})
.catch(error => {
res.status(500).send(error);
})
})
How to debug this situation
Don't automatically assume it is an async issue. First try some simple console.log steps:
const deletePlayer = (id) => {
console.log("Started deletePlayer with id: ",id) ///////////
return new Promise(function(resolve, reject) {
console.log("Inside the promise, id is the same, namely: ",id) ///////////
pool.query('DELETE FROM Players WHERE player_id = ?' , [id], (error,results) => {
if (error) {
reject(error)
}
resolve(`Player deleted with ID: ${id}`)
})
})
}
See if 'id' is what you expect it to be
If you don't see any console.log messages printed, maybe, as #steve16351 suggests, you are editing deletePlayer but actually calling another functiondeletePlayers?
In general, avoid using the word "async" for promises used without the "async" keyword
When Promises first arrived in Javascript, they were the practical tool for asynchronous programming, so people sometimes used the term "async" for them in speech.
However since the async keyword arrived, it is better not to use the word "async" for things that are not that keyword.
Simple glossary
Blocking code: a program that simply waits (preventing any other code running) while some external process happens.
Callbacks: the oldest form of asynchronous programming in JS. You tell JS to run a certain function only after some external event has happened.
Promises: a more convenient and readable way to achieve the same effect as callbacks. You can imagine the process to be constructed out of hidden callbacks.
async keyword: an even more convenient and readable way to achieve the same effects as callbacks and promises. It is implicitly made out of promises, although it protects you from having to think about how to construct a new promise.
In response to you reporting that id is 5 inside the promise
This tells us that your original assumption, that the error is due to a variable being undefined, is incorrect. id has the expected value.
Therefore the error is that the API is giving an error in response to this call:
pool.query(
'DELETE FROM Players WHERE player_id = ?' ,
[5],
(error,results) => {
if (error) {
reject(error)
} else {
resolve(`Player deleted with ID: ${id}`);
}
}
)
So why don't you run exactly that, in simplified form like this:
pool.query(
'DELETE FROM Players WHERE player_id = ?' ,
[5],
(error,results) => {
console.log("Error:",JSON.stringify(error,null,2),"Results:",JSON.stringify(error,null,2))
}
)
This sends an explicit request to pool.query, and explicitly reveals the output. I don't know the format the pool.query API is expecting: perhaps it is not quite right?
Related
Im learning Javascript and im up to a section on Promises.
So decided to try and convert some of my earlier projects to use Promises.
But I cant get my head around it. Iv read a lot of guides and browsed through this site but I still cant understand why this isnt working.
This the function im working with, trying to do a database call that returns a promise, that can then be logged or whatever.
const getID = function (product) {
let query = `select typeID from invTypes where UPPER(typeName) =UPPER('${product}')`;
return new Promise((resolve, reject) => {
resolve(
DB.get(query, function (err, result) {
if (err) {
Bot.say(`Error looking up ${product}`);
} else {
console.log(result.typeID); //587
return result.typeID;
}
})
);
});
};
getID(product).then((data) => console.log(data)); //Database {}
The console outputs
Database {}
587
so the .then(data => console.log(data)) //Database {} Is still happening before the promise is returned,
as you can see the other log from earlier up inside the function is actually logging after it.
Can someone help me with this iv been at this one function for hours now haha. I think I have some kind of fundamental misunderstanding that Im not picking up on from my bootcamp videos or anything im reading.
In promise code, you use resolve() in the asynchronous function's callback function to return values.
const getID = function(product) {
let query = `select typeID from invTypes where UPPER(typeName) =UPPER('${product}')`;
return new Promise((resolve, reject) => {
DB.get(query, function(err, result) {
if (err) {
Bot.say(`Error looking up ${product}`);
reject(`Error looking up ${product}`);
} else {
console.log(result.typeID); //587
resolve(result.typeID);
}
})
});
};
I'm very new to javascript in general and I'm doing a school project that builds a simple lambda function to save some data to DynamoDB from an HTTP request.
First, I had this version:
exports.handler = async (event) => {
var params = {
TableName: 'graph',
ReturnConsumedCapacity: "TOTAL",
Item: null
};
for (let input of event.inputs) {
params.Item = {
'key' : input.key,
'value' : input.value
};
await DynamoDB.DocumentClient.put(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data);
}
});
}
};
To my shallow understanding, an async function like the handler should wait for any await statement to finish executing, but I got nothing in the database. But even for some reasons if the lambda function execution didn't wait for DynamoDB.DocumentClient.put() to finish, wouldn't the DynamoDB.DocumentClient.put() finish on its own after the lambda has returned?
Then I followed some other people's examples and added promise() to the end:
exports.handler = async (event) => {
var params = {
TableName: 'graph',
ReturnConsumedCapacity: "TOTAL",
Item: null
};
for (let input of event.inputs) {
params.Item = {
'key' : input.key,
'value' : input.value
};
await DynamoDB.DocumentClient.put(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data);
}
}).promise();
}
};
Now even though it successfully put data into the database, the log shows 6 'Success' messages where I only put 3 pairs of key-value pairs. After some playing around, I realize the 'Success' messages appear once in the first callback, twice in the second, and three times in the third. I have no clues when it behaves like this at all. Can someone shed some light on this, please? Thank you
You're mixing callbacks and promises. Callbacks were the preferred way to deal with async code (and still is preferred by some i guess), until promises were introduced.
It's not recommended to mix these two for the same purpose.
This would be more correct as you're using the built-in 'then' method of the Promise class:
await DynamoDB.DocumentClient.put(params)
.promise()
.then((data) => {
console.log(data);
})
.catch((err) => {
console.log(err);
});
It doesn't break anything using the callback as well though. Here is a really good answer that explains promises:
Aren't promises just callbacks?
When it comes to it logging 6 times, that doesn't make any sense if the array passed to the loop only has 3 items. If you could provide the output in your original post, I'll see if i can make sense of it and give you an updated answer.
I have a code that looks like this :
app.post("/api/exercise/add", function(req, res, next) {
User
.findById(req.body.userId)
.exec()
.then(user => user)
.then(function(user) {
let exercise = new Exercise({
description: req.body.description,
duration: req.body.duration,
date: req.body.date, //BUG: must add validations, date accepts 19984-01-01
user: user
})
.save()
.then(function(exercise) {
user.exercises.push(exercise)
user.
save().
then(user => res.json({ status: 201, exercises: user.exercises }))
})
.catch(err => next(err))
})
.catch(err => next(err));
});
Is the fact that I'm using a promise inside another promise, in this case, considered an anti-pattern?
In a sense, it's inelegant - the problem is that it creates unnecessary .then nesting. If the .then and .catch handlers that follow both Promises are the same, you can just return the new Promise inside the .then to pass it onto the next .then or .catch, as in the code below.
To pass along multiple variables / Promises to the next .then without reassigning an outer variable, use Promise.all:
app.post("/api/exercise/add", function(req, res, next) {
User
.findById(req.body.userId)
.exec()
.then(function(user) {
// return the Promise so it can be used by the next then, without nesting
// because you also need access to `user` in the next then, use Promise.all
return Promise.all([user, new Exercise({
description: req.body.description,
duration: req.body.duration,
date: req.body.date, //BUG: must add validations, date accepts 19984-01-01
user: user
})
.save()]);
})
.then(function([user, exercise]) {
user.exercises.push(exercise);
// return the Promise so it can be used by the next then, without nesting:
return user.save();
})
.then(user => res.json({ status: 201, exercises: user.exercises }))
.catch(err => next(err));
});
Note that the
.then(user => user)`
is completely superfluous - it doesn't do anything, you already have a Promise that resolves to the user you want in the next .then.
We can have something like this:
new Promise((resolve, reject) => {
let x = 25;
if (x%2 === 0) {
return Promise.resolve('even');
} else {
return Promise.resolve('odd');
}
})
.then(result => {
console.log('the number is '+result);
});
In this case, both the branches of the condition are homogeneous, they both return a string and the result is handled in the same way.
But this not always happens, for example:
new Promise((resolve, reject) => {
if (user.type === 'admin') {
return this.userService.getAdminTools();
} else {
return this.userService.getUserTools();
}
})
.then(result => {
// What type is the result? Maybe in this case, chaining is not the best solution!
});
If you have more branches and the result is not homogeneous, maybe chaining is not the best choice. You can listen to the Promise inside another Promise, or you can just call another method which contains the async code
Your execution flow is now separated into multiple branch which can be a wanted behavior.
When writing code, you should always think about re-usability and readability.
How an other programmer would read and understand my code easily and without getting an headache ?
The way you are putting it together is hard to follow. You should put the asynchronous action you want to perform into a separated function.
Breaking complex stuff into functions are a good practice to use in general, not only in this particular case. Try to have one function to do one thing, and have one execution flow.
User
.findById(req.body.userId)
.exec()
.then(user => user)
.then(user => asynchronousAddUser(user))
.catch(err => next(err));
It is not necessarily an antipattern, but it depends a lot on why are you doing it.
There may be valid reason for breaking the chain and starting a new one, but if you find yourself doing that too often then something is wrong and probably you should rethink your flow.
I see 2 common reasons why people tend to start a new chain
1.A handler at some point during the chain makes a decision based on a condition and each branch has a totally different way of doing its work. At this point is perfectly valid to start a new chain, but I would create a new method that returns a promise. The next handler in the chain must be aware about the fact that it may receive heterogenous data
NewPromise()
.then( res => {
if (someCond) {
return OtherPromise(args)
}
....
return obj
})
.then( res => {
//this promise must be aware that res may be heterogeneous
})
2.During the chain a handler receives some info that you can't easily propagate down the chain. For instance when needing 2 different piece of information that come from a DB and you need both in the end to do the work.
User.findById(uid1)
.then(user1 => {
return User.finById(uid2)
})
.then(user2 => {
// at this point user1 is not available any more
})
A solution for this is to have a variable outside of the chain and not start a new chain
var user1
User.findById(uid1)
.then(user => {
user1 = user
return User.finById(uid2)
})
.then(user2 => {
// at this point user is available and has the value of user1
})
CertainPerformance highlighted in my previous post advised me to avoid the explicit Promise construction antipattern with reference to to following question in stackoverflow
Frankly, Speaking, I am new to JS and node and I haven't used promise a lot. I went and read those article but either I was unable to comprehend or unable to relate or maybe somewhere my understanding of promises have been vague/wrong all together
So I decided to ask this question in a new thread and seek for help.
So what am I doing and why am I doing it
I am creating helper/common function which I could use to keep my code tidy and if in case I want to change anything inside function at anytime, I don't have to manually change every function.
So these are the functions I have made
//Find user by email Address
const findUserByEmail = (emailAddress) => {
return new Promise((resolve, reject) => {
User.findOne({email: emailAddress}).then(response => {
resolve(res)
}).catch(error => {
reject("Error in findUserByEmail", error);
})
})
}
//Create User
const createNewUser = (newUserDetails) => {
return new Promise((resolve, reject) => {
new User({
fullName: newUserDetails.fullName,
email: newUserDetails.email,
image: newUserDetails.image,
gender: newUserDetails.gender,
age: newUserDetails.age
}).save().then((response) => {
resolve(response)
}).catch((error) => {
reject("Problem in Creating New User", error)
})
})
}
Question 1
Now, I am assuming CertainPerformance said the excessive use of promises because I am creating new promise return new Promise((resolve, reject) => { when I am already using promises with mongoose User.findOne({email: emailAddress}).then(response => { ?
But the reason for me to create those promise was, when I call these helper function from anywhere in my app after importing
const { findUserByEmail } = require("./my_db_query");
I would probably want it return a response or throw an error in case of error
findUserByEmail("test#example.com").then(/*...*/).catch(/*...*/);
If I change my above code snippet without adding new promise
function findUserByEmail (email) {
return User.findOne({email: email}).then(currentUser => currentUser).catch(error => error)
}
Question 2
Then I won't probably be able to .then and .catch in findUserByEmail("test#example.com")?
And In API route of App, where I would be calling the findUserByEmail("test#example.com") function, I would want to do something else if there is an error (which would be different for different case and hence I cannot use it in my helper function).
Question 3
Does, it make sense now for doing return new Promise((resolve, reject) => { instead of doing just one return User.findOne( or am I missing something?
Because .findOne already returns a Promise, there's no need to construct a new one with new Promise - instead, just chain onto the existing Promise chain with .then and .catch as needed. Such Promise chains can have any number of .thens and .catchs - just because you consume a Promise with one .then doesn't prevent you from using the same resolve value elsewhere. To illustrate:
makePromise()
.then((result) => {
console.log(result);
// Returning inside a `.then` will pass along the value to the next `.then`:
return result;
})
.then((result) => {
// this `result` will be the same as the one above
});
In other words - there's no need to construct a new Promise every time you want to be able to use another .then. So:
Then I won't probably be able to .then and .catch in findUserByEmail("test#example.com")
isn't correct - you can indeed chain onto the end of an existing Promise with as many .thens and .catches as you want.
Note that a .then which only returns its parameter and does nothing else (such as .then(currentUser => currentUser)) is superfluous - it won't do anything at all. Also note that a .catch will catch Promise rejections and resolve to a resolved Promise. So if you do
function findUserByEmail(email) {
return User.findOne({email: email})
.then(currentUser => currentUser)
.catch(error => error)
}
that catch means that callers of findUserByEmail will not be able to catch errors, because any possible errors were caught in findUserByEmail's catch. Usually, it's a good idea to allow errors to percolate up to the caller of the function, that way you could, for example:
someFunctionThatReturnsPromise('foobar')
.then((result) => {
// everything is normal, send the result
res.send(result);
})
.catch((err) => {
// there was an error, set response status code to 500:
res.status(500).send('there was an error');
})
So, unless your findUserByEmail or createNewUser helper functions need to do something specific when there's an error, it would probably be best just to return the Promise alone:
const findUserByEmail = email => User.findOne(email);
const createNewUser = newUserDetails => new User(newUserDetails).save();
If your helper functions do need to do something when there's an error, then to make sure that the error gets passed along properly to the caller of the function, I'd recommend either throwing the error inside the catch:
const findUserByEmail = email => User.findOne(email)
.catch((err) => {
// error handling - save error text somewhere, do a console.log, etc
throw err;
});
so that you can catch when something else calls findUserByEmail. Otherwise, if you do something like
const findUserByEmail = email => User.findOne(email)
.catch((err) => {
// do something with err
return err;
});
then the caller of findUserByEmail will have to check inside the .then if the result is actually an error, which is weird:
findUserByEmail('foo#bar.com')
.then((result) => {
if (result instanceof Error) {
// do something
} else {
// No errors
}
});
Better to throw the error in findUserByEmail's catch, so that the consumer of findUserByEmail can also .catch.
It never makes sense to create a promise with promise constructor when there's existing promise, that's why it's called promise construction antipattern.
This is a mistake, reject("Error in findUserByEmail", error). reject accepts only 1
argument, which is rejection reason. error will be ignored. It's conventionanl for an error to be Error object and not a string.
The function may be refactored to:
const findUserByEmail = (emailAddress) => {
return User.findOne({email: emailAddress})
.then(response => response) // noop
.catch(error => {
const readableError = new Error('Error in findUserByEmail');
readableError.originalError = error;
throw readableError;
});
})
}
etc.
Antipatterns don't necessary result in bad performance but they result in code smell. They make the code harder to read, maintain and test, also show that a developer may have a poor understanding of the subject.
Promise constructor has some insignificant performance impact. It introduces another level of nesting and contributes to callback hell - promises are supposed to help avoiding it.
If I change my above code snippet without adding new promise <...>
Then I won't probably be able to .then and .catch in findUserByEmail("test#example.com")?
No, a promise can be chained with then(...) and catch(...) (which is syntactic sugar for then(null, ...)) as many times as needed, that's the strong side of the pattern. Notice that catch(err => { return err }) and catch(err => { throw err }) is not the same thing, the former catches an error, the latter rethrows it.
Using sequelize.js in a nodejs app, and I have a promise.all that takes two promises (a user query, and a color query):
router.get(`/someEndPoint`, (req, res) => {
let userAccount = user.findOne({
where: {
id: //some ID
}
});
let colorStuff = color.findOne({
where: {
colorName: //some color
}
})
Promise.all([userAccount , colorStuff ]).then(([result1, result2]) => {
//do stuff, such as:
res.send('success');
}).catch(err => {
console.log(err)
});
});
At the part that says //do stuff, my console keeps giving me this warning:
a promise was created in a handler at... but was not returned from it,
see (URL that I can't post) at Function.Promise.attempt.Promise.try
I'm not sure how to resolve this. I thought after the .then that the promises are resolved?
Hard to tell without other context, but perhaps you need to return the Promise.all
return Promise.all([user, color])...
From the bluebird docs here: https://github.com/petkaantonov/bluebird/blob/master/docs/docs/warning-explanations.md#warning-a-promise-was-created-in-a-handler-but-was-not-returned-from-it
if there are any other promises created in the // do stuff area, be sure to return those as well.