Passing a function result to a parent function [duplicate] - javascript

This question already has answers here:
How to return Mongoose results from the find method?
(6 answers)
Closed 9 years ago.
So I have this method for a User object to check for an existing record.
User.findOrCreate = function(json){
User.findOne({'email' : json.email}, function(err, user){
if (!user){
user = new User({
id: json.id,
email: json.email,
f_name: json.first_name,
l_name: json.last_name,
gender: json.gender,
locale: json.locale
});
user.save(function(err){
if (err) return handleError(err);
return user;
});
} else {
return user;
}
});
}
so basically I want to return the variable "user" to the method findOrCreate, so that I can use it in another place like so:
var user = User.findOrCreate(profile._json);
But instead, user = undefined when I log it out. Having a lot of trouble with this. Can anyone help?

You can't do this:
var user = User.findOrCreate(profile._json);
Because the execution of User.findOne is async, so when findOrCreate returns, probably User.findOne wasn't executed yet.
The right way of getting the user value is to use another callback in findOrCreate:
User.findOrCreate = function(json, callback){
User.findOne({'email' : json.email}, function(err, user){
if (!user){
user = new User({
id: json.id,
email: json.email,
f_name: json.first_name,
l_name: json.last_name,
gender: json.gender,
locale: json.locale
});
user.save(function(err){
if (err) return handleError(err);
callback(user);
});
} else {
callback(user);
}
});
};
As you can see handling all of those callbacks can make you mad. If you didn't tried promises yet take a look to the Q library: http://documentup.com/kriskowal/q/
It will make your life easy:
var userPromise = User.findOrCreate(profile._json);
/* then when you need a user */
userPromise.done(function (user) { /* do something */ });
The advantage is that promises comes with very useful abstractions to handle control flow of async code, for example using promises you can write findOrCreate like this:
User.findOrCreate = function(json) {
return User.findOne({email:json.email}).then(createIfNull);
};
Where createIfNull is the code that you have inside the if block (if save also returns a promise things are easy.. if not you can create one and return it, see Q examples... the docs are not very intuitive but once that you get used to it you'll see that it really simplifies all the callback mess).

The User.getOrCreate function has not any return statement, so of course it will return undefined, in fact findOne is working async, so your getOrCreate function should be async too, So you can change your function definition to:
User.findOrCreate = function(json, callback) {
and instead of return user; you should run the callback function:
callback(user);

Related

callback is not a function (but it is)

Probably this will be an easy question because I don't understand the concept of callback (I thought I did, but apparently no).
I'm trying to return a response from MySQL (easy thing to do in almost every language but with nodeJS):
I'm calling a function from my routes file:
route
const user = require('../models/Users');
router.post('/register', (req, res, next) => {
let newUser = {
username: req.body.username,
password: req.body.password
};
if(user.checkIfUserExists) {
// do something
}
});
And here's the query inside another file:
const mysql = require('../handlers/mysql');
const bcrypt = require('bcrypt-nodejs');
var User = {
checkIfUserExists: function(newUser, callback) {
mysql.query('SELECT * FROM users where Email like ?', [newUser.username], function(err, result) {
if(err) return callback(err);
callback(null, result > 0);
});
},
registerUser: function(newUser) {
mysql.query("INSERT INTO users (Email, Password) VALUES (?, ?)", [newUser.username, User.hashPassword(newUser.password)], function(err, results) {
if (err) throw err;
return true;
});
},
hashPassword: function(password) {
let salt = bcrypt.genSaltSync(10);
return bcrypt.hashSync(password, salt);
}
}
module.exports = User;
Of course, same thing will happen with registerUser
You forget to call and handle the callback.
user.checkIfUserExists(newUser, function(arg1, isUserExist) {
if (isUserExist) {
//user exist
}
});
You are not using callback. To do that follow the below code.
`user.checkIfUserExists(newUser,(result)=>{
If(result){
//write your code
}
}`
Many guys have explained you problem. Let me explain you the concept of callback.
Callback is the function that is called, after a function has finished their job
For example, this function
setTimeout(function(){
alert('Alert will be ran after 3 seconds');
},3000);
You can open the developer mode (hit f12 on your browser and run it). You can see that the alert box will display after 3 seconds. I can explain the flow of code like this.
setTimeout function is run. This function will be finished after 3000 milliseconds, after that it will run the callback function
After 3000 milliseconds, the callback function is called. So the alert box is displayed.
In your code, you just create a plain new object, it does not have the checkIfUserExists function which is from the User object. You have to create user from the User class.
The callback function caused a lot of trouble to beginner, that's why in ES6+ (Javascript Version 6+). The class, async, await are introduced and make life easier.

Best practice of implementing javascript promise

Hi guys I am pretty new to js and asynchronous programming. I use node.js and express to start learning js serverside and asynchronous programming. I have probleom to implement something like callback promise async. I had used callback but I think my code becomes so messy and hard to maintain. Now I try to implement promise in my code below. My question is: do the way I use promise there is a good practice? Cause I think There's no different comparing to callback hell if I implement "nested" promise like my code below. How is the best practice of using promise? Thank you
update_data_profil(req, res) {
var nama_unit_org = req.body.nama_unit_org;
var nama_ketua_unit_org = req.body.nama_ketua_unit_org;
var nip_nim = req.body.nip_nim;
var email = req.body.email;
var no_hp = req.body.no_hp;
var params;
var user;
if (helper.isExist(nama_unit_org) && helper.isExist(nama_ketua_unit_org) && helper.isExist(email)
&& helper.isExist(nip_nim) && helper.isExist(no_hp)) {
if (nip_nim !== req.user.nip_nim) {
params = {
nip_nim: nip_nim
}
user = new User_Model(params);
user.getDataProfilByNIPorNIM()
.then(function (result) {
if (result) {
req.flash('message_err', "NIP/NIM telah dipakai akun lain.");
res.redirect('/manajemen_profil');
}
else {
params = {
id_user: req.user.id_user,
nip_nim: nip_nim,
nama_ketua_unit_org: nama_ketua_unit_org,
nama_unit_org: nama_unit_org,
email: email,
no_hp: no_hp,
};
user = new User_Model(params);
user.editDataProfil()
.then(function () {
params = {
session_id: req.sessionID
};
user = new User_Model(params);
user.clearSession()
.then(function () {
req.flash('message_success', 'Edit data profil berhasil. Silahkan login untuk melanjutkan');
res.render('index/login',
{
message_success: req.flash('message_success')
});
}).catch(function (err) {
req.flash('message_err', "Internal server error");
res.redirect('/');
});
})
.catch(function (err) {
req.flash('message_err', "Internal server error.");
res.redirect('/');
});
}
}).catch(function (err) {
req.flash('message_err', "Internal server error.");
res.redirect('/');
})
}
else {
params = {
id_user: req.user.id_user,
nama_ketua_unit_org: nama_ketua_unit_org,
nama_unit_org: nama_unit_org,
email: email,
no_hp: no_hp
};
user = new User_Model(params);
user.editDataProfil()
.then(function () {
req.flash('message_success', "Berhasil update profil.");
res.redirect('/manajemen_profil');
})
.catch(function (err) {
req.flash('message_err', "Internal server error");
res.redirect('/manajemen_profil');
});
}
}
else {
req.flash('message_err', "Tidak boleh ada field yang kosong!");
res.redirect('/manajemen_profil');
}
}
One of the most beautiful advantages of Nodejs promises is to avoid the callback hell process. And with promises, if you are again nesting one inside the other then you are creating a promise hell ;) .
Below is one of the better approach to use promises.
Chaining:
// Promises example using 'then'
user.getDataProfilByNIPorNIM().then(function(user) {
...
return user.editDataProfil();
}).then(function(editDataProfilResults) {
....
return user.clearSession();
}).then(function(clearSessionResult) {
....
return
}).catch(function(err){
.....
process error
})
I have come across below link, which explain usage of promises. It might be helpful.
https://www.joezimjs.com/javascript/javascript-asynchronous-architectures-events-vs-promises/
For now best practice is to use async/await.
The word async before a function means it always returns a promise. If the code has return
in it, then JavaScript automatically wraps it into a
resolved promise with that value.
The keyword await makes JavaScript wait until that promise settles
and returns its result.
It makes code pretty and easy to handle.
It is quite simple to use, as you can see on following links.
Link 1.
Link 2.
Link 3
Example:
async function getData(url) {
let v;
try {
v = await downloadData(url);
} catch(e) {
v = await downloadFail(url);
}
return processAnother(v);
}
or you can use it like :
async FunctionFun( ) {
const groups = await this.variableGroupsService.find();
const groups2 = await this.pageMarkersService.find();
const groups3 = await this.funnelStepsService.findFunnelSteps()
return anyOtherFunction(groups, groups2, groups3);
}
I'd say best practice as of 2018 is to use async/await instead of using promises in this way.
This article from MDN gives some good examples of how they can be used.
To give a very simple example, a small part of your code using promises:
user.getDataProfilByNIPorNIM()
.then(function (result) {
if (result) {
req.flash('message_err', "NIP/NIM telah dipakai akun lain.");
...
});
could be rewritten as:
try {
const result = await user.getDataProfilByNIPorNIM();
} catch(e) {
// catch errors here.
}
To briefly quote the abovementioned article:
An async function can contain an await expression that pauses the execution of the async function and waits for the passed Promise's resolution, and then resumes the async function's execution and returns the resolved value.
This feature has become a fundamental part of how asynchronous development in Javascript is done in 2018, and I'd personally say it's a de-facto standard.

Using a db query as a promise [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I'm trying to use sql queries as promises. I can't seem to get it to work:
query: (sql, args) => {
if (args) sql = mysql.format(sql, args);
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
if (err) {
console.log(err);
reject(Error(err.code));
}
connection.query(sql, (err, results) => {
connection.release(); // always put connection back in pool after last query
if (err) {
console.log(err);
resolve([]);
}
resolve(results);
});
});
});
},
And here is the query itself:
async function dbCall(sql, arg) {
let data = await db.query(sql, arg);
console.log(data);
data = data[0];
return data;
}
And here is the pool:
var pool = mysql.createPool({
host: 'localhost',
user: 'user',
password: 'pass',
database: 'db',
});
What I'm trying to do:
I'm trying to have it where it doesn't get hung up on async functions. I want it to return a value throughout a whole async function instead of inside of itself only.
Right now, it isn't working at all. However, when it is I would like row to be defined in my whole function instead of just inside the db.query.
I'm not sure if this makes sense, but if you need more clarification just ask anything.
Well if I understand your questions correctly you're misunderstanding how promises should be handled. Promises make use of a then() function to perform something only after the async request is finsihed.
It reads pretty well in plain English. Perform my async request THEN do something with the data.
Try this:
db.query(userSQL, username).then(res => console.log(res))
Additionally, you could use an async function. This allows use to handle async functions in a similar way to synchronous functions where your code will be executed sequentially without having to worry about chaining and nesting other code inside of then() functions
async function dbCall() {
let data = await db.query(userSQL, username);
console.log(data);
}
As a side note. This was super helpful to me when I was first getting into Promises.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

How to return value from a promise that's inside another function?

I know that a lot of questions have been asked about async programming and Promises, but I really need an example with this specific code to figure out how I should go about returning promises that's being returned in another function.
I have two functions. The first one is called upon GET'ing to a route. This route should create a payment link and save a booking to a database.
exports.create_booking = function(req, res) {
req.body.payment = exports.create_booking_payment(req.body.total_amount);
console.log(req.body.payment); // This returns ' Promise { <pending> } '
var new_booking = new Booking(req.body);
new_booking.save(function(err, booking) {
if (err)
res.send(err);
res.json(booking);
});
};
However creating the payment link happens with an asynchronous method. My first problem was that I could only access the payment inside the methods callback function.
Now I have wrapped the method inside another (async) method in which a Promise is created and resolved. This method is being returned to my first method with an await statement, but all this returns is: ' Promise { } '.
I know that this happens because the method is being returned before the promise is resolved. But I don't understand why this is. My assumption is that the 'await' statement makes sure to wait returning the method before the async function is completed.
exports.create_booking_payment = async function() {
function asyncPayment() {
return new Promise (function(resolve, reject) {
mollie.payments.create({
amount: 20.00,
description: "Reservation code: ",
redirectUrl: "https://www.website.com/",
webhookUrl: ""
}, function(payment) {
if (payment.error) reject(payment.error)
else { resolve({
id: payment.id,
link: payment.getPaymentUrl(),
status: payment.status
})
}
});
});
}
return await asyncPayment();
}
I hope someone can help me out here...
You seem to have missed that an async function still returns a promise, not the actual value. So, when you call create_booking_payment(), you are getting back a promise that you need to use either .then() with or await with. There's no free lunch across a function boundary. await allows you to program in a synchronous-like fashion inside a function, but still does not allow you to return the value from the function. When it looks like you're returning the value from the async function, you're actually returning a promise that resolves to that value.
So, you'd do this with async and await:
exports.create_booking = async function(req, res) {
try{
req.body.payment = await exports.create_booking_payment(req.body.total_amount);
console.log(req.body.payment);
var new_booking = new Booking(req.body);
new_booking.save(function(err, booking) {
if (err)
res.status(500).send(err);
else
res.json(booking);
});
} catch(e) {
res.status(500).send(err);
}
};
or this with .then():
exports.create_booking = function(req, res) {
exports.create_booking_payment(req.body.total_amount).then(payment => {
console.log(payment);
req.body.payment = payment;
var new_booking = new Booking(req.body);
new_booking.save(function(err, booking) {
if (err)
res.status(500).send(err);
else
res.json(booking);
});
}).catch(err => {
res.status(500).send(err);
});
};
Note, I also added more complete error handling to both scenarios. Also, this code would be a lot cleaner if you "promisfied" or used an already promisified interface for your .save() method. I strongly dislike using plain callback async code inside of promise-based code because it ends up duplicating error handling (like you see in this case).
Also, create_booking_payment() doesn't need to be async or use await since all you need it to do is to return your promise which it already knows how to do:
exports.create_booking_payment = function() {
return new Promise (function(resolve, reject) {
mollie.payments.create({
amount: 20.00,
description: "Reservation code: ",
redirectUrl: "https://www.website.com/",
webhookUrl: ""
}, function(payment) {
if (payment.error) reject(payment.error)
else { resolve({
id: payment.id,
link: payment.getPaymentUrl(),
status: payment.status
})
}
});
});
}

How to return a variable from a Q Node promise?

I have a learning game using Angular, Express, Mongo and Node. I'm now learning how to use promises, so I can wait until something is finished before starting something else.
Right now, I'm trying to wait until the database says if the user trying to login already have an account. I've succeeded with that, so if the user does not exist, the .then() will call the onReject function that will create the user.
The user have a master account and can play sessions. Within each session, he will receive a new player. If the user exist and tries to login and his player is logged, he will receive that player back. If the player does not exist, the server will create one for him.
But, I'm having a problem with the variable logged, that says if the user have a logged player. On the second line of the function findUser, I'm creating a variable called logged and I'm trying to return it, so I can use on the onResolve function.
UserModel.find(
{ username: username, password: password},
findUser ).then(
onResolve,
onReject );
On Promise resolve
var onResolve = function (logged) {
if (logged) {
//RETURN USER'S PLAYER
} else {
//CREATE USER'S PLAYER
}
}
On Promise reject
var onReject = function () {
userModel.save( function (err) {
if (!err) {
//CREATE USER
//CREATE USER'S PLAYER
}
});
});
Function findUser
var findUser = function (err, data) {
var logged = false;
var userSearched = Q.defer();
if (data.length) { //IF USER IS IN DATABASE
logged = true;
userSearched.resolve(logged);
} else {
userSearched.reject(logged);
}
return userSearched.promise;
};
How could I return the logged variable from the promise to use anywhere I need?
If you return a value from a .then() handler, then that value becomes the fulfilled value of the promise.
var onResolve = function (logged) {
if (logged) {
//RETURN USER'S PLAYER
} else {
//CREATE USER'S PLAYER
}
// ** add this **
return logged;
}
You can then use it in subsequent .then() handlers:
UserModel.find({ username: username, password: password}, findUser)
.then( onResolve, onReject)
.then(function(result) {
// can access result here
});
If this code is inside a function, then you can return the promise from UserModel.find():
function someFunc() {
return UserModel.find({ username: username, password: password}, findUser)
.then( onResolve, onReject);
}
And, then add a .then() handler to the returned promise.
someFunc().then(function(result) {
// access result here
});
Or, in your findUser() function:
var findUser = function (err, data) {
var userSearched = Q.defer();
if (data.length) { //IF USER IS IN DATABASE
userSearched.resolve(true);
} else {
userSearched.reject(false);
}
return userSearched.promise;
};
findUser.then(function(val) {
// access resolved value here
}, function(err) {
// access rejected reason here
});
Though, findUser() does not look asynchronous so I don't really understand why you're using a promise with it at all. It appears you can just return true or false from the function directly.

Categories

Resources