Passing additional parameters to callback - javascript

I am using mssql in node.js executing an SP:
var fnGetMapping = function(results) {
new sql.Request(db.sqlConnection)
.input('myParam', sql.VarChar(60), 'myValue')
.execute('usp_MySP', fnProcessUUIDData);
};
Now my fnProcessUUIDData looks like this:
var fnProcessUUIDData = function(err, recordsets) {
if (err) {
console.log("Error calling MS SQL: " + err.message);
} else {
if (recordsets[0].length > 0) {
} else {
};
}
};
What I need now is to pass one of my own parameter into fnProcessUUIDData.
I read some articles that this is possible but I couldn't get it working on my case, would appreciate some comments if what I want to do is possible.

You can use apply to pass some extra arguments without loosing the context.
new sql.Request(db.sqlConnection)
.input('myParam', sql.VarChar(60), 'myValue')
.execute('usp_MySP', function(...args) {
fnProcessUUIDData.apply(this, args.concat(some, extra, parameters));
});
var fnProcessUUIDData = function(err, recordsets, some, extra, parameters) {
console.log(this, some, extra, parameters);
};

Using apply overcomplicates things because fnProcessUUIDData is a plain old function and not a method (it doesn't use this internally). All you need to do is wrap it in another function:
new sql.Request(db.sqlConnection)
.input('myParam', sql.VarChar(60), 'myValue')
.execute('usp_MySP', function(err, recordsets) {
fnProcessUUIDData(err, recordsets, additional_parameter);
});

Related

Understandings callbacks in javascript and node.js

I understand the concept of callbacks in Javascript. For example this sort of code makes complete sense to me -
function processArray(arr, callback) {
var resultArr = new Array();
for (var i = arr.length-1; i >= 0; i--)
resultArr[i] = callback(arr[i]);
return resultArr;
}
var arr = [1, 2, 3, 4];
var arrReturned = processArray(arr, function(arg) {return arg * -1;});
// arrReturned would be [-1, -2, -3, -4]
I understand that callback is just a placeholder function which could be any function that we write later. However there are certain types of callbacks that I have no clue how to write. For example -
function processData (callback) {
fetchData(function (err, data) {
if (err) {
console.log("An error has occured. Abort everything!");
callback(err);
}
data += 1;
callback(data);
});
}
How is the callback to fetchData defined? How does the program know what is err and what is data?
Normally in node.js the structure of a callback is basically like this function(err, result)
This means that the first argument is the error and the second argument is the data. when you have no error you simply pass a null value. This is a standard already.
The second code you posted you should change it like follows:
function processData (callback) {
fetchData(function (err, data) {
if (err) {
console.log("An error has occured. Abort everything!");
callback(err);
}
data += 1;
callback(null, data);
});
}
In the above case, if you did not want to increase the databy 1 you could simply call fetchData(callback).
My two cents :
In JavaScript everything is object and so does function. So functions can be passed as argument to other functions. This enables you to use callback as arguement and then using those callbacks in your api implementation to execute user's task after accomplishing API's task. Here if you would try to re-read your code then you will realize your misconception. Other users have also quoted the same thing here.
EDIT
function fetchdata(callback){
var err = "This is Error message";
var data = {samplekey : "samplevalue"};
callback(err, data); // here in the implementation of fetchdata
// we are making those data and feeding to the callback function.
}
function callback(err, data){
// Implementation of call back
}
Here for making readable purpose I have put callback function separate. You can pass it simply as well.
I think you do not understand JavaScript completely.
I got this example from here
function doSomething(callback) {
// ...
// Call the callback
callback('stuff', 'goes', 'here');
}
function foo(a, b, c) {
// I'm the callback
alert(a + " " + b + " " + c);
}
doSomething(foo);

Returned object undefined from module function

This has to be a scope issue that I'm not familiar with. I have a small module I've written as so:
(function () {
var getPlanInfo = function (id, conn) {
conn.query('SELECT * FROM `items` WHERE `id` = ?', [id], function (error, result) {
if (error) console.error('Query error: ' + error.stack);
console.log(result[0]); // Everything is great
return result[0];
});
};
modules.exports.getPlanInfo = function (id, conn) { return getPlanInfo(id, conn); // Typo }
})();
Here comes the problem. When I call it from anywhere (inside the module itself or another file), the return value is always undefined. I checked from within the function, the query returns the result as expected.
var backend = require('./module.js');
var t = backend.getPlanInfo();
t is undefined. This is the same if I call that method from inside the module itself (another function within that module).
I'm familiar with the callback principle in javascript and how objects and functions have to be passed around as an argument to remain in scope. Is this the issue here or is this a node.js particularity?
I tried in in the Developer Console (Chrome), works as expected.
conn.query() looks like it is async. Thus, you can't return its result from getPlanInfo() because getPlanInfo() returns long before the result is available. Returning result[0] from the conn.query() callback just returns a piece of data back into the conn.query() infrastructure. getPlanInfo() has long before already returned.
If you want an async result, then you will have to change getPlanInfo() to use a mechanism that supports getting async results such as a direct callback or a promise or something like that.
Here's a plain callback way:
var getPlanInfo = function (id, conn, callback) {
conn.query('SELECT * FROM `items` WHERE `id` = ?', [id], function (error, result) {
if (error) {
console.error('Query error: ' + error.stack);
callback(error);
return;
}
console.log(result[0]); // Everything is great
callback(0, result[0]);
});
};
modules.exports.getPlanInfo = getPlanInfo;
Then, the caller of that module would look like this:
var m = require('whatever');
m.getPlanInfo(id, conn, function(err, result) {
if (err) {
// error here
} else {
// process result here
}
});
You don't return anything from getPlanInfo. Probably you wanted to write modules.exports.getPlanInfo = function (id, conn) { return getPlanInfo; }
(with return getPlanInfo; instead of return getPlanInfo();)

Node.js: How to run asynchronous code sequentially

I have this chunk of code
User.find({}, function(err, users) {
for (var i = 0; i < users.length; i++) {
pseudocode
Friend.find({
'user': curUser._id
}, function(err, friends) * * ANOTHER CALLBACK * * {
for (var i = 0; i < friends.length; i++) {
pseudocode
}
console.log("HERE I'm CHECKING " + curUser);
if (curUser.websiteaccount != "None") {
request.post({
url: 'blah',
formData: blah
}, function(err, httpResponse, body) { * * ANOTHER CALLBACK * *
pseudocode
sendMail(friendResults, curUser);
});
} else {
pseudocode
sendMail(friendResults, curUser);
}
});
console.log("finished friend");
console.log(friendResults);
sleep.sleep(15);
console.log("finished waiting");
console.log(friendResults);
}
});
There's a couple asynchronous things happening here. For each user, I want to find their relevant friends and concat them to a variable. I then want to check if that user has a website account, and if so, make a post request and grab some information there. Only thing is, that everything is happening out of order since the code isn't waiting for the callbacks to finish. I've been using a sleep but that doesn't solve the problem either since it's still jumbled.
I've looked into async, but these functions are intertwined and not really separate, so I wasn't sure how it'd work with async either.
Any suggestions to get this code to run sequentially?
Thanks!
I prefer the promise module to q https://www.npmjs.com/package/promise because of its simplicity
var Promises = require('promise');
var promise = new Promises(function (resolve, reject) {
// do some async stuff
if (success) {
resolve(data);
} else {
reject(reason);
}
});
promise.then(function (data) {
// function called when first promise returned
return new Promises(function (resolve, reject) {
// second async stuff
if (success) {
resolve(data);
} else {
reject(reason);
}
});
}, function (reason) {
// error handler
}).then(function (data) {
// second success handler
}, function (reason) {
// second error handler
}).then(function (data) {
// third success handler
}, function (reason) {
// third error handler
});
As you can see, you can continue like this forever. You can also return simple values instead of promises from the async handlers and then these will simply be passed to the then callback.
I rewrote your code so it was a bit easier to read. You have a few choices of what to do if you want to guarantee synchronous execution:
Use the async library. It provides some helper functions that run your code in series, particularly, this: https://github.com/caolan/async#seriestasks-callback
Use promises to avoid making callbacks, and simplify your code APIs. Promises are a new feature in Javascript, although, in my opinion, you might not want to do this right now. There is still poor library support for promises, and it's not possible to use them with a lot of popular libraries :(
Now -- in regards to your program -- there's actually nothing wrong with your code at all right now (assuming you don't have async code in the pseucode blocks). Your code right now will work just fine, and will execute as expected.
I'd recommend using async for your sequential needs at the moment, as it works both server and client side, is essentially guaranteed to work with all popular libraries, and is well used / tested.
Cleaned up code below
User.find({}, function(err, users) {
for (var i = 0; i < users.length; i++) {
Friend.find({'user':curUser._id}, function(err, friends) {
for (var i = 0; i < friends.length; i++) {
// pseudocode
}
console.log("HERE I'm CHECKING " + curUser);
if (curUser.websiteaccount != "None") {
request.post({ url: 'blah', formData: 'blah' }, function(err, httpResponse, body) {
// pseudocode
sendMail(friendResults, curUser);
});
} else {
// pseudocode
sendMail(friendResults, curUser);
}
});
console.log("finished friend");
console.log(friendResults);
sleep.sleep(15);
console.log("finished waiting");
console.log(friendResults);
}
});
First lets go a bit more functional
var users = User.find({});
users.forEach(function (user) {
var friends = Friend.find({
user: user._id
});
friends.forEach(function (friend) {
if (user.websiteaccount !== 'None') {
post(friend, user);
}
sendMail(friend, user);
});
});
Then lets async that
async.waterfall([
async.apply(Users.find, {}),
function (users, cb) {
async.each(users, function (user, cb) {
async.waterfall([
async.apply(Friends.find, { user, user.id}),
function (friends, cb) {
if (user.websiteAccount !== 'None') {
post(friend, user, function (err, data) {
if (err) {
cb(err);
} else {
sendMail(friend, user, cb);
}
});
} else {
sendMail(friend, user, cb);
}
}
], cb);
});
}
], function (err) {
if (err) {
// all the errors in one spot
throw err;
}
console.log('all done');
});
Also, this is you doing a join, SQL is really good at those.
You'll want to look into something called promises. They'll allow you to chain events and run them in order. Here's a nice tutorial on what they are and how to use them http://strongloop.com/strongblog/promises-in-node-js-with-q-an-alternative-to-callbacks/
You can also take a look at the Async JavaScript library: Async It provides utility functions for ordering the execution of asynchronous functions in JavaScript.
Note: I think the number of queries you are doing within a handler is a code smell. This problem is probably better solved at the query level. That said, let's proceed!
It's hard to know exactly what you want, because your psuedocode could use a cleanup IMHO, but I'm going to what you want to do is this:
Get all users, and for each user
a. get all the user's friends and for each friend:
send a post request if the user has a website account
send an email
Do something after the process has finished
You can do this many different ways. Vanilla callbacks or async work great; I'm going to advocate for promises because they are the future, and library support is quite good. I'll use rsvp, because it is light, but any Promise/A+ compliant library will do the trick.
// helpers to simulate async calls
var User = {}, Friend = {}, request = {};
var asyncTask = User.find = Friend.find = request.post = function (cb) {
setTimeout(function () {
var result = [1, 2, 3];
cb(null, result);
}, 10);
};
User.find(function (err, usersResults) {
// we reduce over the results, creating a "chain" of promises
// that we can .then off of
var userTask = usersResults.reduce(function (outerChain, outerResult) {
return outerChain.then(function (outerValue) {
// since we do not care about the return value or order
// of the asynchronous calls here, we just nest them
// and resolve our promise when they are done
return new RSVP.Promise(function (resolveFriend, reject){
Friend.find(function (err, friendResults) {
friendResults.forEach(function (result) {
request.post(function(err, finalResult) {
resolveFriend(outerValue + '\n finished user' + outerResult);
}, true);
});
});
});
});
}, RSVP.Promise.resolve(''));
// handle success
userTask.then(function (res) {
document.body.textContent = res;
});
// handle errors
userTask.catch(function (err) {
console.log(error);
});
});
jsbin

Node.js concat array after async.concat()

I have an array, I need to recompile with the use of some edits. I do it with the help of async.concat(), but something is not working.
Tell me, where is the mistake?
async.concat(dialogs, function(dialog, callback) {
if (dialog['viewer']['user_profile_image'] != null) {
fs.exists(IM.pathToUserImage + dialog['viewer']['user_profile_image'].replace('%s', ''), function(exits) {
if (exits) {
dialog['viewer']['user_profile_image'] = dialog['viewer']['user_profile_image'].replace('%s', '');
}
callback(dialog);
});
}
}, function() {
console.log(arguments);
});
In my opinion, everything is logical. callback is invoked immediately after the first iteration. But how can I send the data after the completion of processing the entire array?
Thank you!
Instead of callback(dialog);, you want
callback(null,dialog);
because the first parameter to the callback function is an error object. The reason that console.log(arguments) is getting called after the first iteration is because async thinks an error occurred.
I solved the problem but did not understand its meaning. The problem was due to the element which was null instead of the processed value. The program broke off at this point, but do not throw away any errors / warnings.
async.map(dialogs, function(dialog, callback) {
if (dialog['viewer']['user_profile_image'] == null) {
dialog['viewer']['user_profile_image'] = IM.pathToUserImage;
}
fs.exists(IM.pathToUserImage + dialog['viewer']['user_profile_image'].replace('%s', ''), function(exits) {
if (exits) {
dialog['viewer']['user_profile_image'] = dialog['viewer']['user_profile_image'].replace('%s', '');
}
callback(null, dialog);
});
}, function(err, rows) {
if (err) throw err;
console.log(rows);
});
Though I am a little late to post this answer, I see none of us has used .concat function in the way it supposed to be used.
I have created a snippet that says the proper implementation of this function.
let async = require('async');
async.concat([1, 2, 3], hello, (err, result) => {
if (err) throw err;
console.log(result); // [1, 3]
});
function hello(time, callback) {
setTimeout(function () {
callback(time, null)
}, time * 500);
}

What can I use to replace nested async callbacks?

Lets say I wanna send an email then update the database, both actions are async. This is how I would normally write it.
send_email(function(err, id){
if(err){
console.log("error");
}else{
update_database(id,function(err, id){
if(err){
console.log("error");
}else{
console.log("success");
}
});
}
});
I would like to do this instead with middleware.
var mid = {};
mid.send_email = function(){
return function(next){
send_email(function(err,id){
if(err){
console.log("error");
}else{
next(id);
}
});
}
}
mid.update_database = function(){
return function(id,next){
update_database(id,function(err,id){
if(err){
console.log("error");
}else{
next(id);
}
});
}
}
mid.success = function(){
return function(id,next){
console.log("success")
next(id);
}
}
Stacking the middleware.
middleware.use(mid.send_email());
middleware.use(mid.update_database());
middleware.use(mid.success());
There are two main questions at hand.
How can I use middleware in place of nested callbacks?
Is it possible to pass variables to next()?
What you want is to be able to handle a async control flow. Alot of js library can help you to achieve this. You can try the Async library with the waterfall function since you want to be able to pass variables to the next function that will be executed :
https://github.com/caolan/async#waterfall
"Runs an array of functions in series, each passing their results to the next in the array. However, if any of the functions pass an error to the callback, the next function is not executed and the main callback is immediately called with the error."
Example :
async.waterfall([
function(callback){
callback(null, 'one', 'two');
},
function(arg1, arg2, callback){
callback(null, 'three');
},
function(arg1, callback){
// arg1 now equals 'three'
callback(null, 'done');
}
], function (err, result) {
// result now equals 'done'
});
You are probably better off using CommonJS module.exports.
You can create a file like this:
module.exports = function (){
function sendEmail(doneCallback){
// do your stuff, then when you are done:
if(!err){
doneCallback(whatever,args,you,need);
}
}
function updateDB(success){
// do your stuff, then when you are done:
success(whatever,args,you,need);
}
return {
send: sendEmail,
update: updateDB
};
};
Then in your server.js:
var lib = require('./mylib.js');
lib.send(function(result){
console.log(result);
});
This is a similar pattern, and it might give you a better idea of what I mean. It consists of the library baking a function and passing it to whoever needs to chain, like this (more down to earth example, client-side this time):
ui.bistate($('#mybutton'), function(restore){
$.ajax({
url: '/api/1.0/catfood',
type: 'PUT',
data: {
catfood: {
price: 1.23,
name: 'cheap',
text: 'Catzy'
}
}
}).done(function(res){
// stuff with res
restore();
});
});
and in the library, this is how restore is provided:
var ui = function(){
function bistate(button, action) {
var originalText = buttonText.data('text'),
disabledText = buttonText.data('text-disabled');
function restore(){
button.prop('disabled', false);
button.text(originalText);
}
function disable(){
button.prop('disabled', true);
button.text(disabledText);
}
button.on('click', function(){
disable();
action(restore);
});
restore();
}
return {
bistate: bistate
};
}();
Allowing the consumer to control the flow for when he wants to restore the button, and reliving the library from having to handle complex cases where the consumer wants to do an async operation in between.
In general the point is: passing callbacks back and forth is huge and not used widely enough.
I have been using Queue.js in my work for some time.

Categories

Resources