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
})
Related
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
}
})
Hello i have been using a library called deasync it allows me to get things done in a cleaner way, i have a method like this,
syncGetMany: function(model, query){
var ret;
setTimeout(function(){
model.find(query, (error, body) => {
if(body){
//Awesome got the data
ret= body
}
else{
//What a cruel world
// No data, fall back to an empty array
ret = [];
}
});
},0);
while(ret === undefined) {
require('deasync').sleep(0);
}
//returns an empty array or the real data
return ret;
},
Then i simply call it like this.
var data = syncGetMany(MongooseModel, queryObj);
// the rest of my code
QUESTION: is there a way to get this done using ES6, or any similar library.
PS: Not duplicate as other questions are not relevant to my context
simplest way to get this code more cleaner is to use async/await, it's available in node.js version => 7.0. If I think well your model.find method returns promise.
async syncGetMany (model, query) {
let ret;
ret = await model.find(query);
//ret is keeping body from response now, if error occured error is throwed as promise exception
//Could do some sync ops on ret variable
return ret;
}
When you are using async/await you should put your method execution into try/catch. But you can also catch errors inside syncGetMany method, probably it should looks like this:
async syncGetMany(model, query) {
let ret;
try {
ret = await model.find(query);
return ret;
} catch(err) {
console.error(err);
return []; //empty array or any error string/object
}
}
And your execution looks like you wrote with additional await operator (using es6 provide let/const operators for var operator replacement)
let data = await syncGetMany(MongooseModel, queryObj);
Article with async/await explanation:
https://blog.risingstack.com/async-await-node-js-7-nightly/
If you don't want to use Node v7.0 you should code something like this using promises and generators.
https://medium.com/#rdsubhas/es6-from-callbacks-to-promises-to-generators-87f1c0cd8f2e
I hope I helped.
Update
So when your mongoose instance doesn't supports promises there are three options (depends I think on node versions). In my opinion promises are cleaner way to make asynchronous request so I suggest using them.
First option (native promises):
syncGetMany(model, query) {
return new Promise((resolve, reject) => {
model.find(query, (err, res) => {
if(err) {
return reject(err);
}
resolve(res);
});
});
}
Second option (bluebird library, added Async postfix to all methods):
const mongoose = require( 'mongoose' );
const Promise = require('bluebird');
Promise.promisifyAll( mongoose );
async syncGetMany(model, query) {
let ret;
try {
ret = await model.findAsync(query);
return ret;
} catch(err) {
console.error(err);
return []; //empty array or any error string/object
}
}
Third option (Node version => 8.0):
Using native promisify on function:
https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original
On our synchronous part (with async operator before function construction):
let data = await syncGetMany(MongooseModel, queryObj);
You can write and execute logic as if it was synchronous using nsynjs:
function synhronousCode(model, query) {
function syncGetMany(model, query){
return model.find(query).data; // data will contain result of resolved promise at this point
};
var data = syncGetMany(model, query);
// do stuff with data
}
var nsynjs = require('nsynjs');
....
nsynjs.run(synhronousCode,{},model, query, function(){
console.log('synhronousCode done');
});
nsynjs will evaluate code in synhronousCode in sequential manner: if some function returns promise (as model.find does), nsynjs will pause execution and wait until promise is resolved, assigns result to data property of returned value, and then continue execution.
So I'm new to Node.js and Im just wondering if the way I have my code setup makes sense. Im coming from a Java background so the nested callback structure is new. I have a Node program that runs a bunch of code that I broke down into different methods. The thing is that the methods need to be called in order. My code has this structure right now:
functionOne(data, callback(err) {
functionTwo(data, callback(err) {
functionThree(data, callback(err) {
functionFour(data, callback(err) {
//Code
});
});
});
});
This is very minimalistic, but is this structure ok? With Java, I'd take the return values of all the methods, then just pass them to the next function. From my understanding so far, the Java approach I just mentioned is one of the main things that Node.js was trying to eliminate. But anyway... Does that structure look ok, and is that how its intended to look? Just want to be sure that I'm not making any major errors with Node in general. Thanks!
Your code structure looks fine if you work with callback pattern.
But if you're interested in make your code cleaner and readable you would like to use Promises in your asynchronous function, so instead of pass a callback to your functions you could do something like this :
function asyncFunction (data){
return new Promise(function(resolve, reject){
// Do something with data
// Here you can call reject(error) to throw an error
resolve();
});
}
And instead of nested function callbacks you can call then method of Promise.
asyncFunction(data)
.then(function(){
// Promise resolved
// Something has been done with data
});
With Promises you can also execute async fuctions in parallel :
Promise.all([asyncFunctionA(data), asyncFunctionB(data), asyncFunctionC(data)])
.then(function(){...});
EDIT
If you need to pass values of one function to another, your code should look like this :
asyncFunctionA(data)
.then(function(dataA){
return asyncFunctionB(dataA);
})
.then(function(dataB){
return asyncFunctionC(dataB);
})
.then(function(dataC){
// ...
});
You should try to use promises to avoid your callback hell, so it could be something like these...
const Q = require('q'); // you can do a research for this module.
var myModule = {};
myModule.functionOne = (params) => {
const deferred = Q.defer(); // wait for this to complete
// body function
deferred.resolve(data); // this would be the result of this function
return deferred.promise; // data is the output on your function
}
myModule.functionTwo = (params) => {
const deferred = Q.defer(); // wait for this to complete
// body function
deferred.resolve(data); // this would be the result of this function
return deferred.promise; // data is the output on your function
}
myModule.doAll = (params) => {
myModule.functionOne(params)
.then((outputFunctionOne) => {
// this is called after functionOne ends
return myModule.functionTwo(outputFunctionOne);
})
.then((outputFunctionTwo) => {
// this is called after function 2 ends
if (outputFunctionTwo.success) {
// if everything ok, resolve the promise with the final output
deferred.resolve(outputFunctionTwo);
} else {
// reject the promise with an error message
deferred.reject('error');
}
})
.fail((err) => {
// this is call if the promise is rejected or an exception is thrown
console.log(err); // TODO: Error handling
})
.done();
}
module.exports = myModule;
You can Chain as many promises as you want really easily, that way you get rid of the callback hell. Best part, you can do promises on Javascript or Node.js
Reference Link https://github.com/kriskowal/q
Hope this helps
Most of the other answers give Promise/A as the answer to your callback woes. This is correct, and will work for you. However I'd like to give you another option, if you are willing to drop javascript as your working language.
Introducing Iced Coffee, a branch of the CoffeeScript project.
With Iced Coffee you would write:
await functionOne data, defer err
await functionTwo data, defer err2
await functionThree data, defer err3
//etc
This then compiles to the CoffeeScript:
functionOne data, (err) ->
functionTwo data, (err2) ->
functionThree data, (err3) ->
//etc
Which then compiles to your Javascript.
functionOne(data, callback(err) {
functionTwo(data, callback(err2) {
functionThree(data, callback(err3) {
//etc
});
});
});
I'm having trouble with how to properly structure a test for my Promise-returning API with Vows, e.g.
topic:function() { return myfunc() { /* returns a Bluebird Promise */ } },
'this should keep its promise':function(topic) {
var myfunc = topic;
myfunc()
.then(function(result) {
assert(false);
})
.catch(function(error) {
assert(false);
})
.done();
}
My vow never fails. This is my first attempt at using vows to test promises. Hoping someone familiar with this will lend a hand.
In advance, thank you.
Enrique
Since unlike libraries like Mocha - Vows does not yet have support for testing promises, we use its regular asynchronous test format that takes callbacks:
topic:function() { return myfunc() { /* returns a Bluebird Promise */ } },
'this should keep its promise':function(topic) {
var myfunc = topic;
myfunc() // call nodeify to turn a promise to a nodeback, we can chain here
.nodeify(this.callback); // note the this.callback here
}
Here is how it would look with mocha:
describe("Promises", function(){
it("topics", function(){
return myfunc(); // chain here, a rejected promise fails the test.
});
})
The following example is using a when js style promise with vows. You should be able to adapt it to whatever flavor of promise you are using. The key points are:
1) Make sure you call this.callback when your promise resolves. I assign 'this' to a variable in the example below to make sure it is properly available when the promise resolves.
2) Call this.callback (see below how this is done with the variable) with an err object and your result. If you just call it with your result, vows will interpret it as an error.
vows.describe('myTests')
.addBatch({
'myTopic': {
topic: function() {
var vow = this;
simpleWhenPromise()
.then(function (result) {
vow.callback(null, result);
})
.catch(function (err) {
vow.callback(result, null);
});
},
'myTest 1': function(err, result) {
// Test your result
}
},
})
I have code like
common.findOne('list', {'listId': parseInt(request.params. istId)}, function(err, result){
if(err) {
console.log(err);
}
else {
var tArr = new Array();
if(result.tasks) {
var tasks = result.tasks;
for(var i in tasks) {
console.log(tasks[i]);
common.findOne('tasks', {'taskId':parseInt(tasks[i])}, function(err,res){
tArr[i] = res;
console.log(res);
});
}
console.log(tArr);
}
return response.send(result);
}
});
It is not executed sequentially in node.js so I get an empty array at the end of execution. Problem is it will first execute console.log(tArr); and then execute
common.findOne('tasks',{'taskId':parseInt(tasks[i])},function(err,res){
tArr[i] = res;
console.log(res);
});
Is there any mistake in my code or any other way for doing this.
Thanks!
As you are probably aware, things run asynchronously in node.js. So when you need to get things to run in a certain order you need to make use of a control library or basically implement it yourself.
I highly suggest you take a look at async, as it will easily allow you to do something like this:
var async = require('async');
// ..
if(result.tasks) {
async.forEach(result.tasks, processEachTask, afterAllTasks);
function processEachTask(task, callback) {
console.log(task);
common.findOne('tasks', {'taskId':parseInt(task)}, function(err,res) {
tArr.push(res); // NOTE: Assuming order does not matter here
console.log(res);
callback(err);
});
}
function afterAllTasks(err) {
console.log(tArr);
}
}
The main things to see here is that processEachTask gets called with each task, in parallel, so the order is not guaranteed. To mark that the task has been processed, you will call callback in the anonymous function from findOne. This allows you to do more async work in processEachTask but still manage to signify when it is done. When every task is done, it will then call afterAllTasks.
Take a look at async to see all the helper functions that it provides, it is very useful!
I've recently created a simple abstraction named "wait.for" to call async functions in sync mode (based on Fibers): https://github.com/luciotato/waitfor
Using wait.for and async your code will be:
var wait = require('waitfor');
...
//execute in a fiber
function handleRequest(request,response){
try{
...
var result = wait.for(common.findOne,'list',{'listId': parseInt(request.params.istId)});
var tArr = new Array();
if(result.tasks) {
var tasks = result.tasks;
for(var i in tasks){
console.log(tasks[i]);
var res=wait.for(common.findOne,'tasks',{'taskId':parseInt(tasks[i])});
tArr[i] = res;
console.log(res);
}
console.log(tArr);
return response.send(result);
};
....
}
catch(err){
// handle errors
return response.end(err.message);
}
};
// express framework
app.get('/posts', function(req, res) {
// handle request in a Fiber, keep node spinning
wait.launchFiber(handleRequest,req,res);
});