In this code :
if (!parms.script) { // no script... load filename
execscript(parms, function (data){
var text={'result':'success', 'response':data };
if(typeof(data)!='object') {
try {
text.response=JSON.parse(text.response);
} catch(e) {
text={'result':'success','response':data};
}
}
responsehttp.end(JSON.stringify(text));
});
} else {
//parameterised input will replace in script
if(query.paraminput!=undefined) {
var paraminput=qs.parse(query.paraminput);
parms=merge_options(parms, paraminput);
}
execscript(parms, function (data){
var text={'result':'success', 'response':data };
if(typeof(data)!='object') {
try {
text.response=JSON.parse(text.response);
} catch(e) {
text={'result':'success','response':data};
}
}
responsehttp.end(JSON.stringify(text));
});
}
in execscript callback it is called two times , i want to make a single function for executing both call back in if and else .
how can i achieve this .
i tried making seperate function but responsehttp undefinded error camed.
The problem is (I suspect) is that you had your common function declared outside the context of your http response handler and, therefore, responsehttp wasn't defined. Instead create it as a closure function inside your outer function's scope:
function someCallbackYouDontShowInYourQuestion(req, responsehttp) {
// Declare your callback as a closure inside this function, so it
// captures responsehttp state
function callback(data) {
var text={'result':'success', 'response':data };
if(typeof(data)!='object') {
try {
text.response=JSON.parse(text.response);
} catch(e) {
text={'result':'success','response':data};
}
}
responsehttp.end(JSON.stringify(text));
}
if (!parms.script) { // no script... load filename
execscript(parms, callback);
} else {
//parameterised input will replace in script
if(query.paraminput!=undefined) {
var paraminput=qs.parse(query.paraminput);
parms=merge_options(parms, paraminput);
}
execscript(parms, callback);
}
}
callback = function (data){
var text={'result':'success', 'response':data };
if(typeof(data)!='object') {
try {
text.response=JSON.parse(text.response);
} catch(e) {
text={'result':'success','response':data};
}
}
responsehttp.end(JSON.stringify(text));
}
execscript(parms, callback);
Related
I'm new to Node.js, Javascript and callbacks. I have a pretty simple program I'm trying to write and I can't get the callbacks to work.
Here's the relevant code:
var keysfetched = false;
var urlsfetched = false;
function setKeysfetched(){
keysfetched = true;
}
function setUrlsfetched(){
urlsfetched = true;
}
//get list of all media in bucket
getKeys(setKeysfetched);
//get a list of all media urls in DB
getUrls(setUrlsfetched);
//check for media in the bucket which is not used
checkKeys();
function getKeys(callback) {
S3.listObjectsV2(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else{
var contents = data.Contents;
contents.forEach(function (content) {
allKeys.push(content.Key);
});
if (data.IsTruncated) {
params.ContinuationToken = data.NextContinuationToken;
//console.log("get further list...");
getKeys();
}
else{
console.log("end of loop...");
}
}
});
callback()
}
When I run this I get an error : Error [TypeError]: callback is not a function
If I comment out all of the code inside getKeys(), I don't get the error.
This runs just fine:
function getKeys(callback) {
//Hard work here
callback()
}
What am I doing wrong?
You are passing callback and calling it at the bottom of getKeys but inside you are not passing any callback
if (data.IsTruncated) {
params.ContinuationToken = data.NextContinuationToken;
//console.log("get further list...");
getKeys();
}
So it's trying to call undefined which is not a function.
I have just started to learn nodejs. I have come across this problem please can anyone show me how to fix this?? I'm unable to send the parameter to the function. I just comes empty.
var getLocation = function(link, callback) {
console.log(link); //it comes empty | no value
if (cond.) {
console.log("stuff");
} else {
var location = value;
callback(location);
}
}
getTable(link) {
var session = obj.createSession();
session.table(id, 20, function(err, table) { //this block does some stuff work.
responseCb(link.id, link.jx, err, table);
console.log("extracted.");
});
getLocation(function(link, callback) { //this block sends links as parameter
console.log(callback);
});
}
function main() {
idList = [{
id: "",
jx: ""
}]; //contain data in the array.
for (var i = 0; i < idList.length; i++) {
getTable(idList[i]);
}
}
main();
Your getLocation function accepts two parameters: link and callback. When you call it however you only pass in a single argument:
getLocation(function(link, callback) { //this block sends links as parameter
console.log(callback);
});
You pass in a function that has the same parameters as the function that you are calling (getLocation). This doesn't make any sence. I assume that what you actually wanted to do was the following:
getLocation(link, function() {
console.log(location);
});
Pass the link to the function.
Pass a callback to the function.
In the callback, do something with the location.
My code looks similar to that:
var mongo_client = require('mongodb').MongoClient, dataStorage;
lib = {
[...]
find: function(res, param, callback) {
var parentPath = param.path;
while (parentPath !== '/') {
collection.findOne({'paths' : parentPath}, {...}, function(err, data)) {
if (data) {
dataStorage = data;
callback(data, res);
}
}
if (dataStorage) {
return;
}
parentPath = lib.removeLastBlockOfPath(parentPath);
}
if (!dataStorage) {
callback(someDefaultData, res);
}
}
[...]
}
What I want to do is to find some path stored in mongo, or if there is no match, try do find first matching parent path.
I can't set dataStorage value from findOne callback is it any way to do that? Eaven if I find path it always run thru all path blocks.
Node is asynchronous, so your code must be written accordingly. An option is to use the async module, that has lots of tools to manage asynchronous flows.
For example, you could use the whilst function to manage your while loop:
find: function(res, param, callback) {
var parentPath = param.path,
dataStorage = null;
async.whilst(
function () { return parentPath !== '/'; },
function (done) {
collection.findOne({'paths' : parentPath}, {...}, function(err, data) {
if (data) {
dataStorage = data;
return callback(data, res);
}
parentPath = lib.removeLastBlockOfPath(parentPath);
done();
});
},
function (error) {
if (!dataStorage) return callback(someDefaultData, res);
}
);
}
Don't forget to install and require the async module:
var async = require('async');
Your code is written as if it is "traditional synchronous" -- which its not. You cannot check for dataStorage validity till results from findOne() come back -- so your checks need to be moved all the way into the inner "if (data)" statement. This is not a mongodb issue, this is purely how nodejs works and the fact that everything is asynchronous and works on callbacks.
Basically, I want to pit two asynchronous calls against each other, and only use the winner.
I cannot seem to figure out how to do this, only how to prevent it. Is it remotely possible?
Lame pseudo-code:
//rigging a race
function MysqlUser()
{
setTimeout(function(){
return "mysqluser";
}, 500);
}
function ADUser()
{
setTimeout(function(){
return "aduser";
}, 1000);
}
function getUser()
{
var user = null;
user = ADBind();
user = MysqlBind();
//if user != null
return user;
//else?
}
I'd like (in this instance) for MysqlUser to win out over ADUser.
Any help would be appreciated.
You can write a simple first function that takes a list of task and calls back with the result of only the first to complete:
function first(tasks, cb) {
var done = false;
tasks.forEach(function(task) {
task(function(result) {
if(done) return;
done = true;
cb(result);
});
});
}
Then:
function mysqlUser(cb) {
setTimeout(function() {
cb("mysqluser");
}, 500);
}
function adUser(cb) {
setTimeout(function() {
cb("aduser");
}, 1000);
}
first([mysqlUser, adUser], function(user) {
console.log(user);
});
This might need some more thought if you want to cope with both operations failing.
I've written a node script that gets some data by requesting REST API data (using the library request). It consists of a couple of functions like so:
var data = { /* object to store all data */ },
function getKloutData() {
request(url, function() { /* store data */}
}
// and a function for twitter data
Because I want to do some stuff after fetching all the I used the library async to run all the fetch functions like so:
async.parallel([ getTwitterData, getKloutData ], function() {
console.log('done');
});
This all works fine, however I wanted to put everything inside a object pattern so I could fetch multiple accounts at the same time:
function Fetcher(name) {
this.userID = ''
this.user = { /* data */ }
this.init();
}
Fetcher.prototype.init = function() {
async.parallel([ this.getTwitterData, this.getKloutData ], function() {
console.log('done');
});
}
Fetcher.prototype.getKloutData = function(callback) {
request(url, function () { /* store data */ });
};
This doesn't work because async and request change the this context. The only way I could get around it is by binding everything I pass through async and request:
Fetcher.prototype.init = function() {
async.parallel([ this.getTwitterData.bind(this), this.getKloutData.bind(this) ], function() {
console.log('done');
});
}
Fetcher.prototype.getKloutData = function(callback) {
function saveData() {
/* store data */
}
request(url, saveData.bind(this);
};
Am I doing something basic wrong or something? I think reverting to the script and forking it to child_processes creates to much overhead.
You're doing it exactly right.
The alternative is to keep a reference to the object always in context instead of using bind, but that requires some gymnastics:
Fetcher.prototype.init = function() {
var self = this;
async.parallel([
function(){ return self.getTwitterData() },
function(){ return self.getKloutData() }
], function() {
console.log('done');
});
}
Fetcher.prototype.getKloutData = function(callback) {
var self = this;
function saveData() {
// store data
self.blah();
}
request(url, saveData);
};
You can also do the binding beforehand:
Fetcher.prototype.bindAll = function(){
this.getKloutData = this.prototype.getKloutData.bind(this);
this.getTwitterData = this.prototype.getTwitterData.bind(this);
};
Fetcher.prototype.init = function(){
this.bindAll();
async.parallel([ this.getTwitterData, this.getKloutData ], function() {
console.log('done');
});
};
You can save this into another variable:
var me = this;
Then me is your this.
Instantiate object with this function:
function newClass(klass) {
var obj = new klass;
$.map(obj, function(value, key) {
if (typeof value == "function") {
obj[key] = value.bind(obj);
}
});
return obj;
}
This will do automatic binding of all function, so you will get object in habitual OOP style,
when methods inside objects has context of its object.
So you instantiate you objects not through the:
var obj = new Fetcher();
But:
var obj = newClass(Fetcher);