User.prototype.isUnique = function () {
var result;
db.user.count({name:'abcdefg'}, function(err, count){
console.log('the count is: ' + count);
result = count;
});
return result;
}
this function is used to find out if this user is unique, but the return result is always 'undefined' since db operation is async. I believe it is a common problem in nodejs.
How do I solve it?
I try to use promise (https://npmjs.org/package/promise), but I don't have enough knowledge to understand their documentation. It's for very advanced developer.
Can you help me with some sample code? All I need to do is get the count() using mongoskin, and then return the result in this member method.
Thanks!
It's not a common problem, it's just how Node works and something that you'll have to get used to dealing with.
The simplest solution (also a very common one) is to provide a callback function from the calling code. That function will be called whenever the asynchronous action is finished:
User.prototype.isUnique = function(callback) {
db.user.count({name:'abcdefg'}, function(err, count){
console.log('the count is: ' + count);
callback(err, count);
});
}
// in your calling code:
user.isUnique(function(err, count) {
if (err) ...; // TODO: handle error
...
});
It's also common in Node to have callback functions accept at least one argument which contains an error object if an error occurred, or null if everything went okay.
In the code above I'm passing any errors that may have occurred during the call to db.user.count to the callback function. It's up to the calling code to deal with any errors.
There are several alternatives to dealing with asynchronous code. One would be to use promises, like you mention. There are also solutions like streamline that make asynchronous code look like it is synchronous, but it requires that you 'compile' your code (although this can also be done at runtime) before you can use it.
EDIT: if you want to use promises, you can use this:
var Promise = require('promise');
User.prototype.isUnique = function() {
return Promise(function(resolve, reject) {
db.user.count({name:'abcdefg'}, function(err, count){
if (err) {
console.log('an error occurred:', err);
reject(err);
} else {
console.log('the count is:', count);
resolve(count);
}
});
});
};
// in your calling code:
user.isUnique().then(function(count) {
...
}, function(err) {
...
});
(this requires that the promise package is installed)
Related
I am trying to return jsonObj below and it is not returning. Help would be appreciated. Here fileName is the path of the file which I need to read. And again, I need to return jsonObj. So I can access it outside fs.readFile function.``
Here is the code
return fs.readFile(fileName, 'utf-8', (err, fileContent) => {
if(err) {
console.log(err); // Do something to handle the error or just throw it
throw new Error(err);
}
let jsonObj = csvjson.toObject(fileContent);
console.log(jsonObj)
return jsonObj
});
In Node you don't return from a callback function, that gets discarded and ignored. You must either use Promises, possibly in conjunction with async/await, or you must accept a callback function of your own.
This is the founding principle of asynchronous code:
// The fs.readFile() function executes immediately
fs.readFile(..., (err, ...) => {
// This code runs in the distant future, like imagine ten years from now
// from the perspective of the computer.
});
// JavaScript continues here immediately.
The readFile function does not return anything in particular, the inner function has not yet been run. It's also worth noting that throwing exceptions in there is pointless, don't do it.
To chain:
function getData(fileName, cb) {
fs.readFileName(fileName, 'utf-8', (err, fileContent) => {
if (err) {
// Back-propagate the error
return cb(err);
}
// Engage the callback function with the data
cb(null, csvjson.toObject(fileContent));
}
}
Note that this code is a lot less convoluted and messy if you use promises instead.
I have this function which gets some data from my database but i'm having a trouble calling the function and getting the proper response
function getEvents()
{
var x = [];
var l = dbCollection['e'].find({}).forEach(function(y) {
x.push(y);
});
return x;
});
and another function which calls this function but it always returns undefined.
How can i make the function wait till mongoose has finished filling up the array?
Thanks for the help! My life
dbCollection['e'].find is called non-blocking way so you are returning x before filling. You need to use callbacks or some mongoose promises. You can get all returning values from database like following snippet
function getEvents(callback) {
dbCollection['e'].find({}, function(error, results) {
// results is array.
// if you need to filter results you can do it here
return callback(error, results);
})
}
Whenever you need to call getEvents function you need to pass a callback to it.
getEvents(function(error, results) {
console.log(results); // you have results here
})
You should read mongoose docs for how queries work.
There is also support for promises in mongoose. You can check this url for more information about promises.
The solution proposed by #orhankutlu should work fine.
I will give another solution using promise. You can choose one between these two solutions depending on your style of programming.
Solution using promise:
function getEvents() {
return new Promise(function(resolve, reject){
dbCollection['e'].find({}, function(error, results) {
if (error) return reject(error);
var x = [];
results.forEach(function(y){
x.push(y);
});
// forEach() is a blocking call,
// so the promise will be resolved only
// after the forEach completes
return resolve(x);
});
});
};
Calling getEvents():
getEvents().then(function(result){
console.log(result); //should print 'x'
}).catch(function(err){
// Handle error here in case the promise is rejected
});
I will encourage you to try both the approaches, ie, using callbacks and using promises. Hope you find it useful!
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
});
});
});
Where are people getting cb() from, is this a Node thing or vanilla JS thing?
For example:
Managing Node.js Callback Hell with Promises, Generators and Other Approaches
they're using cb() to I guess callback and return an error or a value or both in some cases depending on what the callback function sig is?
cb in the context you're describing it is how a vanilla callback function is passed into a (typically) asynchronous function, which is a common pattern in node.js (it's sometimes labelled next, but you can call it bananas if you so desire - it's just an argument).
Typically the first argument is an error object (often false - if all went as planned) and subsequent arguments are data of some form.
For example:
function myAsyncFunction(arg1, arg2, cb) {
// async things
cb(false, { data: 123 });
}
then using this function:
myAsyncFunction(10, 99, function onComplete(error, data) {
if (!error) {
// hooray, everything went as planned
} else {
// disaster - retry / respond with an error etc
}
});
Promises are an alternative to this design pattern where you would return a Promise object from myAsyncFunction
For example:
function myAsyncFunction2(arg1, arg2) {
return new Promise(function resolution(resolve, reject, {
// async things
resolve({ data: 123 });
});
}
then using this function:
myAsyncFunction2(10, 99)
.then(function onSuccess(data) {
// success - send a 200 code etc
})
.catch(function onError(error) {
// oh noes - 500
});
They're basically the same thing, just written slightly differently. Promises aren't supported especially widely in a native form, but if put through a transpiler (I'd recommend babel) during a build step they should perform reliably enough in a browser too.
Callbacks will always work in a browser with no shimming / transpilation.
node.js has lots of asynchronous operations that take a completion callback as an argument. This is very common in various node.js APIs.
The node.js convention for this callback is that the first argument passed to the callback is an error code. A falsey value for this first argument means that there is no error.
For example:
fs.readFile("test.txt", function(err, data) {
if (!err) {
console.log("file data is: " + data);
}
});
A function you create yourself may also define it's own callback in order to communicate the end of one or more asynchronous operations.
function getData(id, cb) {
var fname = "datafile-" + id + ".txt";
fs.readFile(fname, function(err, data) {
if (err) {
cb(err);
} else if (data.slice(0, 6) !== "Header"){
// proper header not found at beginning of file data
cb(new Error("Invalid header"));
} else {
cb(0, data);
}
});
}
// usage:
getData(29, function(err, data) {
if (!err) {
console.log(data);
}
});
From the Vanilla JS, you can declare a function and pass throuw parameters a declaration of another function, that can called async
https://developer.mozilla.org/en-US/docs/Glossary/Callback_function
I'm trying to promisify a 3rd party library that doesn't use the callback(err, data) pattern. Instead they always return callback(data) and throw on errors.
Promise.promisifyAll(horse);
var p = Promise.defer();
horse.drinkAsync()
.error(function(data)
{
p.fulfill(data);
})
.catch(function (err)
{
console.error('error occured', err);
});
return p.promise;
What is a nice way to wrap such a behavior with promises and still have it look ok and allow to catch the thrown error? The catch clause doesn't trigger and the application crashes.
From Bluebird 2.1 on, you can now customize promisifyAll with a custom promisification handler:
function noErrPromisifier(originalMethod){
return function promisified() {
var args = [].slice.call(arguments); // might want to use smarter
var self = this // promisification if performance critical
return new Promise(function(resolve,reject){
args.push(resolve);
originalMethod.apply(self,args); // call with arguments
});
};
}
var horse = Promise.promisifyAll(require("horse"), {
promisifier: noErrPromisifier
});
horse.drinkAsync().then(function(data){
// Can use here, ow promisified normally.
});
If the original method throws asynchronously, there is really no way around wrapping it in a domain, although I've never seen a library that acts that poorly.