NodeJS callback variable assignation is always one update behind - node.js

I'm learning NodeJS and I have the following code:
var test = '';
function test2(name,callback) {
UserData
.findOne({'token': name})
.then(function(user) {
test = user.token;
console.log('current: '+user.token);
return callback(user.token);
})
.catch(function(err) {
console.log(err);
});
}
var isAuthenticated = function(req,res,next){
test2(req.cookies.remember_me, function(user) {test=user; });
console.log('test:::: '+test);
var isLog = false;
if(req.session.user!= undefined && req.session.user===test){
isLog=true;
}
if(req.cookies.remember_me ===test){
console.log('test'+test);
isLog=true;
}
if(isLog){
return 1;
}else
{
console.log('not auth');
return -1;
}
}
and the result is :
test:::: P9Ysq2oSCHy1RVyWsePxJhpEYLD81qOiIayTyiNJCnOkmllvEspwrDAW8tD9rmfJ
not auth
current: k8LJcCty6568QpXNS3urBedlJ0MDfEYlbOqo9Q7tQi9EOyeSkyesgHHzUjBhDgZx
I know it's bcause if the async nature of NodeJS but how can i make test to be always the same as 'current';
Thank you.

You are making a pretty classic mistake of expecting code to run in the order written, but it doesn't because of the async nature of javascript. For example:
test2(req.cookies.remember_me, function(user) {test=user; });
console.log('test:::: '+test);
Here your console.log() will run before the callback because the callback only happens after you've heard back from the DB. (Although it's not clear where that test value ('P9Ysq2oSCH...') is coming from.
As long as you're learning Node, you should start by trying to avoiding mixing callbacks and promises. Your findOne() function returns a promise, which is why you can call then() on it. You should just return this promise and then call then() in the calling function:
function test2(name) {
// return is important - you're returning the promise which you will use later.
return UserData.findOne({'token': name})
.then(function(user) {
return user.token;
})
.catch(function(err) {
console.log(err);
});
}
function isAuthenticated(req,res,next){
return test2(req.cookies.remember_me)
.then(function(token) {
console.log('test:::: '+token);
var isLog = false;
if(req.session.user!= undefined && req.session.user===token){
isLog=true;
}
if(req.cookies.remember_me ===token){
isLog=true;
}
return isLog
})
}
// Use the function
isAuthenticated(req,res,next)
.then(function(isLoggedin){
if(isLoggedin) {
// user logged in
} else {
// not logged in
}
})

Related

rethinkdb & nodejs: save result in var

it's possible save result query of rethinkdb in a variable?
Like this??
var test = r.db('chat').table('group_chat').count(r.row('passengers').contains(function(passeggers) {
return passeggers('nome').eq('pigi');
})).run()
now I use this method
var test;
r.db('chat').table('group_chat').count(r.row('passengers').contains(function(passeggers) {
return passeggers('nome').eq('pigi');
})).run().then(function(response){
test = response;
})
If you don't like using promises and are using the latest version of ECMAScript, you can use async/await, which provides syntactic sugar to let you write your asynchronous code as if it were synchronous.
You could rewrite your example like this:
async function getTest() {
var test = await r.db('chat').table('group_chat').count(r.row('passengers').contains(function(passeggers) {
return passeggers('nome').eq('pigi');
})).run();
return test;
}
Note that “behind the scenes”, this still uses promises, but it makes the code easier to read and understand.
Simplest yet working solution would be as bellow, using callback
function getTest(callback) { // add callback
r.db('chat')
.table('group_chat')
.count(r.row('passengers')) // you forgot closing brace here
.contains(function(passeggers) {
return passeggers('nome').eq('pigi')
})
.run()
.then(function(result) {
callback(null, result); // call callback with result
})
.error(function(err) {
callback(err, null); // call callback with error
});
}
getTest(function(err, result) { // invoke callback
if (err) throw err;
console.log(result)
var test = result; // note: you can use test variable only inside this call
})

How to handle conditional callbacks using Promises(Bluebird) in NodeJS

I am currently trying to refactor the codebase that I have and want to have a more developer friendly codebase. Part 1 of that is changing callback to Promises. Currently, at some places we are using Async.waterfall to flatten the callback hell, which works for me. The remaining places where we couldn't was because they were conditional callbacks, That means different callback function inside if and else
if(x){
call_this_callback()
}else{
call_other_callback()
}
Now I use bluebird for promises in Node.JS and I can't figure out how to handle conditional callback to flatten the callback hell.
EDIT
A more realistic scenario, considering I didn't get the crux of the issue.
var promise = Collection1.find({
condn: true
}).exec()
promise.then(function(val) {
if(val){
return gotoStep2();
}else{
return createItem();
}
})
.then(function (res){
//I don't know which response I am getting Is it the promise of gotoStep2
//or from the createItem because in both the different database is going
//to be called. How do I handle this
})
There is no magic, you can easily chain promises with return inside a promise.
var promise = Collection1.find({
condn: true
}).exec();
//first approach
promise.then(function(val) {
if(val){
return gotoStep2()
.then(function(result) {
//handle result from gotoStep2() here
});
}else{
return createItem()
.then(function(result) {
//handle result from createItem() here
});
}
});
//second approach
promise.then(function(val) {
return new Promise(function() {
if(val){
return gotoStep2()
} else {
return createItem();
}
}).then(function(result) {
if (val) {
//this is result from gotoStep2();
} else {
//this is result from createItem();
}
});
});
//third approach
promise.then(function(val) {
if(val){
return gotoStep2(); //assume return array
} else {
return createItem(); //assume return object
}
}).then(function(result) {
//validate the result if it has own status or type
if (Array.isArray(result)) {
//returned from gotoStep2()
} else {
//returned from createItem()
}
//you can have other validation or status checking based on your results
});
Edit: Update sample code because author updated his sample code.
Edit: Added 3rd approach to help you understand promise chain
Here is the answer to the promise branch: nested and unnested.
Make the branches and don't join them together.

How to handle callbacks in Node.js?

Let's say I have 3 files.
index.js makes a call to the backend like this
$.post('/test/', data, function(response) {
//handle success here
})
routes.js handles the route like this
app.post('/test/', function(req, res){
item.getItems(function(response){
res.json(response);
});
});
items.js is the model which accesses the database and makes a POST request for each item
function getItems(callback) {
database.query('SELECT * from items', function(result){
result.forEach(function(item){
request.post('/api/', item, function(req, res) {
//finished posting item
});
});
});
//callback here doesnt wait for calls to finish
}
where/when should I call the callback passed to getItems() to handle a success/failure in index.js?
Because your request.post() operations are async, you have to use some method of keeping track of when they are all done and then you can call your callback. There are multiple ways of doing that. I'll outline a few:
Manually Keeping Track of Count of Request Operations
function getItems(callback) {
database.query('SELECT * from items', function(result){
var remaining = result.length;
result.forEach(function(item){
request.post('/api/', item, function(err, res) {
--remaining;
//finished posting item
if (remaining === 0) {
callback();
}
});
});
});
}
The main problem with doing this manually is that propagating error in nested async operations is difficult when you get to actually figuring out how you're going to handle errors. This is much easier in the other methods shown here.
Using Promises
// load Bluebird promise library
var Promise = require('bluebird');
// promisify async operations
Promise.promisifyAll(request);
function queryAsync(query) {
return new Promise(function(resolve, reject) {
// this needs proper error handling from the database query
database.query('SELECT * from items', function(result){
resolve(result);
});
});
}
function getItems(callback) {
return queryAsync('SELECT * from items').then(function(result) {
return Promise.map(result, function(item) {
return request.postAsync('/api/', item);
});
});
}
getItems.then(function(results) {
// success here
}, function(err) {
// error here
})
It seems strange that you're making an API request in your server-side code, unless this is some sort of middle tier code that interacts with the API... but you're interacting with a database, so I'm still confused on why you can't just do a database insert, or have a bulk insert API call?
Anyway, if you must do it the way you're asking, I've done this in the past with a recursive method that trims down the result array... I really don't know if this is a good approach, so I'd like to hear any feedback. Something like this:
function recursiveResult(result, successfulResults, callback) {
var item = result.shift();
// if item is undefined, then we've hit the end of the array, so we'll call the original callback
if (item !== undefined) {
console.log(item, result);
// do the POST in here, and in its callback, call recursiveResult(result, successfulResults, callback);
successfulResults.push(item);
return recursiveResult(result, successfulResults, callback);
}
// make sure callback is defined, otherwise, server will crash
else if (callback) {
return callback(successfulResults);
}
else {
// log error... callback undefined
}
}
function getItems(callback) {
var successfulResults = [];
var result = [1, 2, 3, 4];
recursiveResult(result, successfulResults, callback);
}
console.log('starting');
getItems(function(finalResult) {
console.log('done', finalResult);
});

function not returning value to client from server

I have a function to access mongodb using mongoose, the database call works and appears in the console but it doesn't return that array as it should. Can't figure out why.
exports.getPrices = function() {
return Price.find().exec(function (err, docs) {
if (err) {
return err;
}
console.log(docs);
return docs;
});
};
the call from the service
angular.module('core')
.factory('Machineprice', [ '$http',
function($http) {
return {
getPrices:function(){
return $http.get('/getPrices')
}
};
}
]
);
the controller
angular.module('core').controller('MachinePricingController', ['$scope','Machineprice',
function($scope, Machineprice) {
$scope.prices = Machineprice.getPrices();
console.log($scope.prices);
}
]);
It's not working because the getPrices() runs asynchronously which means it doesn't return the result instantly. That function returns a promise which means the result has to be dealt with in a callback function.
Quote from AngularJS site:
The $http service is a function which takes a single argument — a
configuration object — that is used to generate an HTTP request and
returns a promise.
To make it work, you have to change the code of your controller.
angular.module('core').controller('MachinePricingController', ['$scope', 'Machineprice',
function ($scope, Machineprice) {
Machineprice.getPrices().then(function (response) {
$scope.prices = response.data;
console.log($scope.prices);
});
}]);

NodeJS Q Promise erroring "has no method 'then'"

I'm working on implementing a promise (first time using them with node) but I keep getting the error:
TypeError: Object function (){
Users.findById(req.body.receiver).exec(function (err, user){
if(err) return handleError(err);
if(user.local.email ){
return email = user.local.email
}
if(user.facebook.email){
return email = user.facebook.email
}
})
} has no method 'then'
Judging by the error I'm going to have to guess there is something wrong with return function()?
Here is my function:
exports.sendEmail = function(req,res){
function findEmail(){
return function(){
Users.findById(req.body.receiver).exec(function (err, user){
if(err) return handleError(err);
if(user.local.email ){
return email = user.local.email
}
if(user.facebook.email){
return email = user.facebook.email
}
})
}
}
findEmail().then(function(email){
// do stuff
})
}
function findEmail(){
return function(){
return Q();
};
}
findEmail(); // returns a function
In your example the findEmail returns a function that if called returns a promise. However your attempting to use the returned function as if it was a promise which it isn't it's a function.
Two ways to fix:
findEmail()(); // returns the promise
Or refactor the function:
function findEmail() {
return Q();
}
findEmail(); // returns the promise
Notice the missing return function()?
Too much nesting? Do you really need that extra function wrapper?
exports.sendEmail = function(req,res){
function findEmail(){
Users.findById(req.body.receiver).exec(function (err, user){
if(err) return handleError(err);
if(user.local.email ){
return email = user.local.email
}
if(user.facebook.email){
return email = user.facebook.email
}
})
}
findEmail().then(function(email){
// do stuff
})
}
EDIT: I would also do some serious refactoring here, promisify stuff (mixing callbacks and promises is just not great visually, promisified code looks a lot better), avoid a named function if it's only used internally and once, etc...

Resources