Node JS Async Response - javascript

I wrote my 1st application in Node.js with MongoDB and I came across the situation where I need to have 2 db.collection.update statements depending on an IF/ELSE condition.
I am trying to return back the operation details in a resJSON JS object but seems like callback is executing before the db.collection.update statements are completed and the default value of resJSON is getting back in response each time.
detail code:
var url = require('url');
var fs = require('fs');
var async = require('async');
var passwordGen = require('../../lib/passwordGen');
var http = require("http");
var server = http.createServer();
server.on('request', request);
server.listen(8080,'127.0.0.1');
function request(request, response) {
var userData = '';
request.on('data', function(data)
{
userData += data;
});
request.on('end', function()
{
async.auto({
allProcess: function(callback){
var resJSON = {'inserted':0,'disabled':0,'error':''};
var jsonData = JSON.parse(userData);
if(jsonData.length > 0){
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect("mongodb://localhost:27017/test_db", function(err,db){
if(err) { return console.dir(err); }
var collection = db.collection('users');
var arrDisableRec = [];
for(i=0;i<jsonData.length;i++){
var action = jsonData[i]['action'].toLowerCase();
if(action == 'disable'){
arrDisableRec.push(jsonData[i]['email']);
}else{
var date = new Date();
var obj = {
'createdISO':date,
'created':date,
'updated':date,
'updatedISO':date,
'email':jsonData[i]['email'],
'firstName':jsonData[i]['firstname'],
'lastName':jsonData[i]['lastname'],
'password':passwordGen.getPassword(),
'enabled':true,
'active':true,
'downloaded':true,
'defaultServings':2,
'name':''
};
collection.update(
{'email':jsonData[i]['email']},
{$setOnInsert:obj},
{upsert: true},
function(err,numberAffected,rawResponse) {
if(typeof numberAffected.result.upserted != 'undefined'){
resJSON['inserted'] = resJSON['inserted'] + numberAffected.result.upserted.length;
}
if(typeof numberAffected.result.nModified != 'undefined'){
resJSON['disabled'] = resJSON['disabled'] + parseInt(numberAffected.result.nModified);
}
if(typeof numberAffected.result.writeError != 'undefined'){
resJSON['error'] ='Error Code:'+(numberAffected.result.writeError.code)+', '+numberAffected.result.writeError.errmsg;
}
console.log(resJSON); //shows correct values
}
);
}
if(arrDisableRec.length > 0){
collection.update(
{'email':{$in:arrDisableRec}},
{$set:{'enabled':false}},
{multi:true},
function(err,numberAffected,rawResponse) {
if(typeof numberAffected.result.upserted != 'undefined'){
resJSON['inserted'] = resJSON['inserted'] + numberAffected.result.upserted.length;
}
if(typeof numberAffected.result.nModified != 'undefined'){
resJSON['disabled'] = resJSON['disabled'] + parseInt(numberAffected.result.nModified);
}
if(typeof numberAffected.result.writeError != 'undefined'){
resJSON['error'] ='Error Code:'+(numberAffected.result.writeError.code)+', '+numberAffected.result.writeError.errmsg;
}
console.log(resJSON); //shows correct values
}
);
}
}
});
}
callback(resJSON);
}
},function(resJSON){
response.writeHead(200,{
'Content-Type': 'text/json'
});
response.end(JSON.stringify(resJSON)); //replies back with default resJSON only.
});
});
}
Any suggestions/directions please?
Thanks

You have to call the callback at then end of the callback chain.
For example
console.log(resJSON); //shows correct values
callback(null, resJSON);
you will have to make sure that every callback chain end point calls the callback. To handle the for loop you will have to have a mechanism to join all the end points of all the async calls done inside the for loop.
for example
if(err) {
return callback(err);
}
notice that I used the function callback(err, res) standard node prototype instead of your function callback(res)
better yet, use an async flow library like async or a promise library like bluebird

This is a counter solution for your issue. It should solve your case for now. Try reading async library. It will be very useful for later.
var counter = 0;
function commoncallback(err,numberAffected,rawResponse) {
if(typeof numberAffected.result.upserted != 'undefined'){
resJSON['inserted'] = resJSON['inserted'] + numberAffected.result.upserted.length;
}
if(typeof numberAffected.result.nModified != 'undefined'){
resJSON['disabled'] = resJSON['disabled'] + parseInt(numberAffected.result.nModified);
}
if(typeof numberAffected.result.writeError != 'undefined'){
resJSON['error'] ='Error Code:'+(numberAffected.result.writeError.code)+', '+numberAffected.result.writeError.errmsg;
}
console.log(resJSON); //shows correct values
counter --;
if(counter == 0) callback(resJSON); //call your main call back here
}
for (i=0; i<jsonData.length; i++) {
if(firstCase) {
counter ++;
collection.update({'email':{$in:arrDisableRec}},
{$set:{'enabled':false}},
{multi:true},commoncallback);
} else {
//another update action
counter++;
}
}

Related

Multiple sockets override itself

My Code
I want to make a multiple connection to a telnet console. This project is for Teamspeak and Teamspeak just communicate with telnet. I´ve a object that create a telnet connection as socket with the net lib. If we have just one instance to connect all works fine and I get the serverlist over the telnet connection back. But if I´ve two instance he says invalid loginname or password. That login informations are correct and he also try just to connect to one server.
My Class:
/*
Teamspeak query client class
#instance: Instance object of the teamspeak query client
*/
function TeamspeakQueryClient(instance) {
events.EventEmitter.call(this);
var $this = this,
socket = net.connect(instance.port, instance.ip),
reader = null,
skipLines = -2,
queue = [ ],
executing = null,
server = null;
this.Type = 'Unknown';
this.Id = null;
this.Connected = false;
this.Banned = false;
/*
Socket settings
*/
socket.setKeepAlive(true, 60000);
/*
Socket connect to the teamspeak instance
*/
socket.on("connect", function() {
reader = LineInputStream(socket);
reader.on("line", function(line) {
var s = line.trim();
console.log(line);
// Skipp the first lines
if(skipLines < 0){
if(line === 'TS3') {
this.Type = 'Teamspeak';
};
skipLines++;
if(skipLines === 0) {
checkQueue();
if(server === null) {
$this.SendCommand("login", {client_login_name: instance.client, client_login_password: instance.password}, function(err, response, rawResponse) {
console.log(err);
if(err === null) {
if(err.id === 3329) {
$this.Banned = true;
};
$this.CloseSocket();
} else {
$this.SendCommand("serverlist", null, function(err, response, rawResponse){
console.log(response);
if(response[0] === undefined) {
console.log('1 server');
} else {
console.log('mehrere server');
};
//console.log(rawResponse);
/*cl.send("clientlist", function(err, response, rawResponse){
console.log(util.inspect(response));
});*/
});
};
});
} else {
console.log(server);
};
};
return;
};
// Parse server request
var response = undefined;
if(s.indexOf("error") === 0){
response = parseResponse(s.substr("error ".length).trim());
executing.error = response;
if(executing.error.id === 0) delete executing.error;
if(executing.cb) executing.cb.call(executing, executing.error, executing.response,
executing.rawResponse);
executing = null;
checkQueue();
} else if(s.indexOf("notify") === 0){
s = s.substr("notify".length);
response = parseResponse(s);
$this.emit(s.substr(0, s.indexOf(" ")), response);
} else if(executing) {
response = parseResponse(s);
executing.rawResponse = s;
executing.response = response;
};
});
$this.emit("connect");
});
/*
Socket error
*/
socket.on("error", function(err){
log.LogLine(1, 'TeamspeakQueryClient: We got a error');
log.LogLine(1, 'Message: '+err);
$this.emit("error", err);
});
/*
Socket close
*/
socket.on("close", function(){
log.LogLine(3, 'TeamspeakQueryClient: Socket from '+instance.alias+' closeing...');
$this.emit("close", queue);
});
/*
Function to send a custom command to the telnet console
*/
TeamspeakQueryClient.prototype.SendCommand = function SendCommand() {
var args = Array.prototype.slice.call(arguments);
//console.log(args);
var options = [], params = {};
var callback = undefined;
var cmd = args.shift();
args.forEach(function(v){
if(util.isArray(v)){
options = v;
} else if(typeof v === "function"){
callback = v;
} else {
params = v;
}
});
var tosend = tsescape(cmd);
options.forEach(function(v){
tosend += " -" + tsescape(v);
});
for(var k in params){
var v = params[k];
if(util.isArray(v)){ // Multiple values for the same key - concatenate all
var doptions = v.map(function(val){
return tsescape(k) + "=" + tsescape(val);
});
tosend += " " + doptions.join("|");
} else {
tosend += " " + tsescape(k.toString()) + "=" + tsescape(v.toString());
}
}
queue.push({cmd: cmd, options: options, parameters: params, text: tosend, cb: callback});
if(skipLines === 0) checkQueue();
};
/*
Function to close the socket
*/
TeamspeakQueryClient.prototype.CloseSocket = function CloseSocket() {
socket.destroy();
$this.emit("close");
};
/*
Function to parse a string to a object
#s: String of the object that will be parsed
#return: Object of the parsed string
*/
function parseResponse(s){
var response = [];
var records = s.split("|");
response = records.map(function(k){
var args = k.split(" ");
var thisrec = { };
args.forEach(function(v) {
if(v.indexOf("=") > -1) {
var key = tsunescape(v.substr(0, v.indexOf("=")));
var value = tsunescape(v.substr(v.indexOf("=")+1));
if(parseInt(value, 10) == value) value = parseInt(value, 10);
thisrec[key] = value;
} else {
thisrec[v] = "";
};
});
return thisrec;
});
if(response.length === 0) {
response = null;
} else if(response.length === 1) {
response = response.shift();
};
return response;
};
/*
Function to write commands into the socket
*/
function checkQueue() {
if(!executing && queue.length >= 1){
executing = queue.shift();
socket.write(executing.text + "\n");
};
};
/*
Function to escape a telnet string
#s: String that want to be escaped
#return: The escaped string
*/
function tsescape(s) {
return s
.replace(/\\/g, "\\\\")
.replace(/\//g, "\\/")
.replace(/\|/g, "\\p")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
.replace(/\t/g, "\\t")
.replace(/\v/g, "\\v")
.replace(/\f/g, "\\f")
.replace(/ /g, "\\s");
};
/*
Function to unescape a telnet string
#s: String that want to be unescaped
#return: The unescaped string
*/
function tsunescape(s) {
return s
.replace(/\\s/g, " ")
.replace(/\\p/g, "|")
.replace(/\\n/g, "\n")
.replace(/\\f/g, "\f")
.replace(/\\r/g, "\r")
.replace(/\\t/g, "\t")
.replace(/\\v/g, "\v")
.replace(/\\\//g, "\/")
.replace(/\\\\/g, "\\");
};
};
util.inherits(TeamspeakQueryClient, events.EventEmitter);
How I open the class
if I call example one all works fine but example two has the descriped error.
Example 1:
test1 = new TeamspeakQueryClient({
"alias": "First-Coder Testinsance",
"ip": "first-coder.de",
"port": 10011,
"client": "serveradmin",
"password": "SECURE"
});
Example 2:
test1 = new TeamspeakQueryClient({
"alias": "First Insance",
"ip": "HIDDEN",
"port": HIDDEN,
"client": "serveradmin",
"password": "SECURE"
});
test2 = new TeamspeakQueryClient({
"alias": "Second Instance",
"ip": "HIDDEN",
"port": HIDDEN,
"client": "serveradmin",
"password": "SECURE"
});
Screenshots
Picture of the error in the console
According to your error, your second instance is not sending the correct login:
error id=520 msg=invalid\sloginname\sor\spassword
The additional errors displayed are due to your code not handling errors correctly.
For example:
socket.on("connect", function() {
...
if(err === null) {
if(err.id === 3329) {
If err === null, why would err have an element id?
Most likely this is code error, and you actually meant err !== null
$this.SendCommand("serverlist", null, function(err, response, rawResponse){
console.log(response);
if(response[0] === undefined) {
This error triggers because the (above) previous error was not caught.
At this point, the client is not logged in (authorized).
So when the serverlist command is sent, it riggers another error.
This additional error is also no handled, instead response is immediately used.

Nodejs + Q promise + method return based on url type

I am using node js for backend, also using q promise package.
Question : I am trying to get third party product details.
1. www.abcd.com 2. www.xyz.com - this method i handle in backend.
Possible url:
localhost:8080/search?type="abcd";
localhost:8080/search?type="xyz";
localhost:8080/search;
If the above URL type is abcd means need to search some different thridparty(www.abcd.com) http url;
If the above URL type is xyz means need to search some other different thridparty(www.xyz.com) http url
If the above URL didn't get type means need to search www.abcd.com if the result found means then return response, if result not found means need to call www.xyz.com url and then return response. (Note - here two third party api need to call)
Code:
router.get('/search', function(req, res, next) {
if (!( typeof req.query === 'undefined' || req.query === null || req.query == "")) {
var type = req.query;
}
var spec = {
resp : {}
};
Q(spec).then(function(spec) {
var deferred = Q.defer();
var optionsget = {
host : 'abcd.com',
method : 'GET'
};
var reqGet = https.request(optionsget, function(res) {
var getProductInfo = '';
res.on('data', function(d) {
getProductInfo += d;
});
res.on('end', function() {
if (( typeof message == 'undefined') && (!( typeof items === 'undefined' || items === null))) {
spec.resp.list = items;
deferred.resolve(spec);
} else {
spec.resp.message = message;
deferred.reject(spec);
}
});
});
reqGet.end();
reqGet.on('error', function(e) {
console.log(e);
deferred.reject(spec);
});
return deferred.promise;
}).then(function(spec) {
var deferred = Q.defer();
var optionsget = {
host : 'xyz.com',
method : 'GET'
};
var reqGet = https.request(optionsget, function(res) {
var getProductInfo = '';
res.on('data', function(d) {
getProductInfo += d;
});
res.on('end', function() {
if (( typeof message == 'undefined') && (!( typeof items === 'undefined' || items === null))) {
spec.resp.list = items;
deferred.resolve(spec);
} else {
spec.resp.message = message;
deferred.reject(spec);
}
});
});
reqGet.end();
reqGet.on('error', function(e) {
console.log(e);
deferred.reject(spec);
});
return deferred.promise;
}).then(function(spec) {
spec.resp.status = 'Success';
res.send(spec.resp);
}).fail(function(spec) {
spec.resp.status = 'Error';
res.send(spec.resp);
});
});
I this is chilly question. I understand need to check the type and implement. I thought we need to add some different function for both (abcd and xyz) then can call that method based on type.
Please suggest to good way.

Interaction in a Dynamic action between javascript and plsql tasks

I'm trying to execute several pl/sql blocks in a Dynamic Action, with feedback to the end user with a modal dialog reporting the current satus.
Something like:
Processing Step 1...
/*Run pl/sql code for step 1*/
Processing Step 2...
/*Run pl/sql code for Step 2*/
and so on...
Both, the pl/sql and javascript code, run as intended but when I combined them on a Dynamic Action in the sequence:
1 - Execute Javascript
2 - Execute PL/SQL block /* With wait for result option checked*/
3 - Execute Javascript
4 - Execute PL/SQL block
The status dialog is not been shown, however the pl/sql blocks are completed without problems.
I realize that this must be something related to javascript not been multithreaded, so I've moved the pl/sql block to application processes and run them as ajax calls like this:
function something(){
var get;
var result = 0;
updateStatus('Running Step1');
get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=P6_STEP_1',0);
result = get.get();
if(result > 0){
updateStatus('Running Step 2');
get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=P6_STEP_2',0);
result = get.get();
}
closeStatusDialog();
}
But still, as before, the processes run fine but the dialog doesn't appear. Finally I added a setTimeOut function to each call, like this:
function something(){
var get;
var result = 0;
updateStatus('Running Step1');
get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=P6_STEP_1',0);
result = setTimeOut(get.get(),500);
if(result > 0){
updateStatus('Running Step 2');
get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=P6_STEP_2',0);
result = setTimeOut(get.get(),500);
}
closeStatusDialog();
}
But still nothing. What can I do to get this running as needed?.
I've checked the browser console and no exeptions are been thrown, likewise with the pl/sql blocks.
I've solved it, although the solution doesn't rely on dynamic actions, just javascript and applicacion processes. I'm posting this for anyone with a similar problem.
The htmldb_Get Javascript object is an oracle-apex wrapper for the XMLHttpRequest AJAX object. Poorly documented though.
I've found a copy of the code (at the bottom) and it turns out it has another function called GetAsync that allows to pass a function as a parameter to asign it to the onreadystatechange attribute on the XMLHttpRequest object, which will be executed each time the attribute readyState of the underlying XMLHttpRequest changes.
The function passed as a parameter can't have parameters on its own definition.
So, instead of calling get() on the htmldb_Get object you need to call GetAsync(someFunction)
With this solution in my case:
function something(){
var get;
get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=P6_STEP_1',0);
get.GetAsync(someFunctionStep1);
}
function someFunctionStep1(){
if(p.readyState == 0){ /*p is the underlying XMLHttpRequest object*/
console.log("request not initialized");
updateStatus('Running Step 1');
} else if(p.readyState == 1){
console.log("server connection established");
} else if(p.readyState == 2){
console.log("request received");
} else if(p.readyState == 3){
console.log("processing request");
} else if(p.readyState == 4){
console.log("request finished and response is ready");
callStep2();
}
}
function callStep2(){
var get;
get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=P6_STEP_2',0);
get.GetAsync(someFunctionStep2);
}
function someFunctionStep2(){
if(p.readyState == 0){
console.log("request not initialized");
updateStatus('Running Step 2');
} else if(p.readyState == 1){
console.log("server connection established");
} else if(p.readyState == 2){
console.log("request received");
} else if(p.readyState == 3){
console.log("processing request");
} else if(p.readyState == 4){
console.log("request finished and response is ready");
closeDialog();
}
}
Here's the htmldb_get definition, at the end is the GetAsync function
/*
str should be in the form of a valid f?p= syntax
*/
function htmldb_Get(obj,flow,req,page,instance,proc,queryString) {
//
// setup variables
//
this.obj = $x(obj); // object to put in the partial page
this.proc = proc != null ? proc : 'wwv_flow.show'; // proc to call
this.flow = flow != null ? flow : $x('pFlowId').value; // flowid
this.request = req != null ? req : ''; // request
this.page = page; // page
this.params = ''; // holder for params
this.response = ''; // holder for the response
this.base = null; // holder fot the base url
this.queryString = queryString!= null ? queryString : null ; // holder for passing in f? syntax
this.syncMode = false;
//
// declare methods
//
this.addParam = htmldb_Get_addParam;
this.add = htmldb_Get_addItem;
this.getPartial = htmldb_Get_trimPartialPage;
this.getFull = htmldb_Get_fullReturn;
this.get = htmldb_Get_getData;
this.url = htmldb_Get_getUrl;
this.escape = htmldb_Get_escape;
this.clear = htmldb_Get_clear;
this.sync = htmldb_Get_sync;
this.setNode = setNode;
this.replaceNode = replaceNode
//
// setup the base url
//
var u = window.location.href.indexOf("?") > 0 ?
window.location.href.substring(0,window.location.href.indexOf("?"))
: window.location.href;
this.base = u.substring(0,u.lastIndexOf("/"));
if ( this.proc == null || this.proc == "" )
this.proc = u.substring(u.lastIndexOf("/")+1);
this.base = this.base +"/" + this.proc;
//
// grab the instance form the page form
//
if ( instance == null || instance == "" ) {
var pageInstance = document.getElementById("pInstance");
if ( typeof(pageInstance) == 'object' ) {
this.instance = pageInstance.value;
}
} else {
this.instance = instance;
}
//
// finish setiing up the base url and params
//
if ( ! queryString ) {
this.addParam('p_request', this.request) ;
this.addParam('p_instance', this.instance);
this.addParam('p_flow_id', this.flow);
this.addParam('p_flow_step_id',this.page);
}
function setNode(id) {
this.node = html_GetElement(id);
}
function replaceNode(newNode){
var i=0;
for(i=this.node.childNodes.length-1;i>=0;i--){
this.node.removeChild(this.node.childNodes[i]);
}
this.node.appendChild(newNode);
}
}
function htmldb_Get_sync(s){
this.syncMode=s;
}
function htmldb_Get_clear(val){
this.addParam('p_clear_cache',val);
}
//
// return the queryString
//
function htmldb_Get_getUrl(){
return this.queryString == null ? this.base +'?'+ this.params : this.queryString;
}
function htmldb_Get_escape(val){
// force to be a string
val = val + "";
val = val.replace(/\%/g, "%25");
val = val.replace(/\+/g, "%2B");
val = val.replace(/\ /g, "%20");
val = val.replace(/\./g, "%2E");
val = val.replace(/\*/g, "%2A");
val = val.replace(/\?/g, "%3F");
val = val.replace(/\\/g, "%5C");
val = val.replace(/\//g, "%2F");
val = val.replace(/\>/g, "%3E");
val = val.replace(/\</g, "%3C");
val = val.replace(/\{/g, "%7B");
val = val.replace(/\}/g, "%7D");
val = val.replace(/\~/g, "%7E");
val = val.replace(/\[/g, "%5B");
val = val.replace(/\]/g, "%5D");
val = val.replace(/\`/g, "%60");
val = val.replace(/\;/g, "%3B");
val = val.replace(/\?/g, "%3F");
val = val.replace(/\#/g, "%40");
val = val.replace(/\&/g, "%26");
val = val.replace(/\#/g, "%23");
val = val.replace(/\|/g, "%7C");
val = val.replace(/\^/g, "%5E");
val = val.replace(/\:/g, "%3A");
val = val.replace(/\=/g, "%3D");
val = val.replace(/\$/g, "%24");
//val = val.replace(/\"/g, "%22");
return val;
}
//
// Simple function to add name/value pairs to the url
//
function htmldb_Get_addParam(name,val){
if ( this.params == '' )
this.params = name + '='+ ( val != null ? this.escape(val) : '' );
else
//this.params = this.params + '&'+ name + '='+ ( val != null ? val : '' );
this.params = this.params + '&'+ name + '='+ ( val != null ? this.escape(val) : '' );
return;
}
//
// Simple function to add name/value pairs to the url
//
function htmldb_Get_addItem(name,value){
this.addParam('p_arg_names',name);
this.addParam('p_arg_values',value);
}
//
// funtion strips out the PPR sections and returns that
//
function htmldb_Get_trimPartialPage(startTag,endTag,obj) {
setTimeout(html_processing,1);
if (obj) {this.obj = $x(obj);}
if (!startTag){startTag = '<!--START-->'};
if (!endTag){endTag = '<!--END-->'};
var start = this.response.indexOf(startTag);
var part;
if ( start >0 ) {
this.response = this.response.substring(start+startTag.length);
var end = this.response.indexOf(endTag);
this.response = this.response.substring(0,end);
}
if ( this.obj ) {
if(this.obj.nodeName == 'INPUT'){
if(document.all){
gResult = this.response;
gNode = this.obj;
var ie_HACK = 'htmldb_get_WriteResult()';
setTimeout(ie_HACK,100);
}else{
this.obj.value = this.response;
}
}else{
if(document.all){
gResult = this.response;
gNode = this.obj;
var ie_HACK = 'htmldb_get_WriteResult()';
setTimeout(ie_HACK,100);
}else{
this.obj.innerHTML = this.response;
}
}
}
//window.status = 'Done'
setTimeout(html_Doneprocessing,1);
return this.response;
}
var gResult = null;
var gNode = null
function htmldb_get_WriteResult(){
if(gNode && ( gNode.nodeName == 'INPUT' || gNode.nodeName == 'TEXTAREA')){
gNode.value = gResult;
}else{
gNode.innerHTML = gResult;
}
gResult = null;
gNode = null;
return;
}
//
// function return the full response
//
function htmldb_Get_fullReturn(obj) {
setTimeout(html_processing,1);
if (obj) { this.obj = html_GetElement(obj);}
if ( this.obj ) {
if(this.obj.nodeName == 'INPUT'){
this.obj.value = this.response;
}else{
if(document.all){
gResult = this.response;
gNode = this.obj;
var ie_HACK = 'htmldb_get_WriteResult()';
setTimeout(ie_HACK,10);
}else{
this.obj.innerHTML = this.response;
}
}
}
setTimeout(html_Doneprocessing,1);
return this.response;
}
//
// Perform the actual get from the server
//
function htmldb_Get_getData(mode,startTag,endTag){
html_processing();
var p;
try {
p = new XMLHttpRequest();
} catch (e) {
p = new ActiveXObject("Msxml2.XMLHTTP");
}
try {
var startTime = new Date();
p.open("POST", this.base, this.syncMode);
p.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
p.send(this.queryString == null ? this.params : this.queryString );
this.response = p.responseText;
if ( this.node )
this.replaceNode(p.responseXML);
if ( mode == null || mode =='PPR' ) {
return this.getPartial(startTag,endTag);
} if ( mode == "XML" ) {
setTimeout(html_Doneprocessing,1);
return p.responseXML;
} else {
return this.getFull();
}
} catch (e) {
setTimeout(html_Doneprocessing,1);
return;
}
}
function html_Doneprocessing(){
document.body.style.cursor="default";
}
function html_processing(){
document.body.style.cursor="wait";
}
/*
this adds better aysnc functionality
to the htmldb_Get object
pVar is the function that you want to call when the xmlhttp state changes
in the function specified by pVar the xmlhttp object can be referenced by the variable p
*/
htmldb_Get.prototype.GetAsync = function(pVar){
try{
p = new XMLHttpRequest();
}catch(e){
p = new ActiveXObject("Msxml2.XMLHTTP");
}
try {
var startTime = new Date();
p.open("POST", this.base, true);
if(p) {
p.onreadystatechange = pVar;
p.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
p.send(this.queryString == null ? this.params : this.queryString );
return p;
}
}catch(e){
return false;
}
}
/* PDF OUTPUT */
/*Gets PDF src XML */
function htmldb_ExternalPost(pThis,pRegion,pPostUrl){
var pURL = 'f?p='+html_GetElement('pFlowId').value+':'+html_GetElement('pFlowStepId').value+':'+html_GetElement('pInstance').value+':FLOW_FOP_OUTPUT_R'+pRegion
document.body.innerHTML = document.body.innerHTML + '<div style="display:none;" id="dbaseSecondForm"><form id="xmlFormPost" action="' + pPostUrl + '?ie=.pdf" method="post" target="pdf"><textarea name="vXML" id="vXML" style="width:500px;height:500px;"></textarea></form></div>';
var l_El = html_GetElement('vXML');
var get = new htmldb_Get(l_El,null,null,null,null,'f',pURL.substring(2));
get.get();
get = null;
setTimeout('html_GetElement("xmlFormPost").submit()',10);
return;
}
function $xml_Control(pThis){
this.xsl_string = '<?xml version="1.0"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="html"/><xsl:param name="xpath" /><xsl:template match="/"><xsl:copy-of select="//*[#id=$xpath]"/></xsl:template></xsl:stylesheet>';
if(document.all){
this.xsl_object = new ActiveXObject("Msxml2.FreeThreadedDOMDocument.3.0");
this.xsl_object.async=false;
this.xsl_object.loadXML(this.xsl_string)
tmp = new ActiveXObject("Msxml2.XSLTemplate.3.0");
tmp.stylesheet = this.xsl_object;
this.xsl_processor = tmp.createProcessor();
}else{
this.xsl_object = (new DOMParser()).parseFromString(this.xsl_string, "text/xml");
this.xsl_processor = (new XSLTProcessor());
this.xsl_processor.importStylesheet(this.xsl_object);
this.ownerDocument = document.implementation.createDocument("", "test", null);
}
this.xml = pThis;
this.CloneAndPlace = _CloneAndPlace;
return
function _CloneAndPlace(pThis,pThat,pText){
var lThat = $x(pThat);
if(document.all){
this.xsl_processor.addParameter("xpath", pThis);
this.xsl_processor.input = this.xml;
this.xsl_processor.transform;
var newFragment = this.xsl_processor.output;
}else{
this.xsl_processor.setParameter(null, "xpath", pThis);
var newFragment = this.xsl_processor.transformToFragment(this.xml,this.ownerDocument);
}
if(lThat){
if(document.all){
lThat.innerHTML='';
lThat.innerHTML=newFragment;
}else{
lThat.innerHTML='';
lThat.appendChild(newFragment);
}
/*
in IE newFragment will be a string
in FF newFragment will be a dome Node (more useful)
*/
return newFragment;
}
}
}

Javascript for loop wait for callback

I have this function:
function tryStartLocalTrendsFetch(woeid) {
var userIds = Object.keys(twitClientsMap);
var isStarted = false;
for (var i = 0; i < userIds.length; i++) {
var userId = userIds[i];
var twitClientData = twitClientsMap[userId];
var isWoeidMatch = (woeid === twitClientData.woeid);
if (isWoeidMatch) {
startLocalTrendsFetch(woeid, twitClientData, function (err, data) {
if (err) {
// Couldn't start local trends fetch for userId: and woeid:
isStarted = false;
} else {
isStarted = true;
}
});
// This will not obviously work because startLocalTrendsFetch method is async and will execute immediately
if (isStarted) {
break;
}
}
}
console.log("No users are fetching woeid: " + woeid);
}
The gist of this method is that I want the line if (isStarted) { break; } to work. The reason is that if it's started it should not continue the loop and try to start another one.
I'm doing this in NodeJS.
try to use a recursive definition instead
function tryStartLocalTrendsFetch(woeid) {
var userIds = Object.keys(twitClientsMap);
recursiveDefinition (userIds, woeid);
}
function recursiveDefinition (userIds, woeid, userIndex)
var userId = userIds[userIndex = userIndex || 0];
var twitClientData = twitClientsMap[userId];
var isWoeidMatch = (woeid === twitClientData.woeid);
if (isWoeidMatch && userIndex<userIds.length) {
startLocalTrendsFetch(woeid, twitClientData, function (err, data) {
if (err) {
recursiveDefinition(userIds, woeid, userIndex + 1)
} else {
console.log("No users are fetching woeid: " + woeid);
}
});
} else {
console.log("No users are fetching woeid: " + woeid);
}
}
You may also use async (npm install async):
var async = require('async');
async.forEach(row, function(col, callback){
// Do your magic here
callback(); // indicates the end of loop - exit out of loop
}, function(err){
if(err) throw err;
});
More material to help you out: Node.js - Using the async lib - async.foreach with object

possible nested asynchronous function

So I have read a lot of the different answers about asynchronous functions on here but I think I am over thinking my problem, or I have been staring at it just to long and I cant figure it out. So your help is greatly appreciated.
So I am parsing a csv file and then trying to get the lat/long through another api. but I cant access the lat/lng outside of the function. below is my code I have commented it to the best of my ability please let me know if there are any questions or a much better way to do this.
Thanks,
var location = []
function run() {
http.get(url, function(res) {
if(res.statusCode === 200) {
res.pipe(parse(function(err, data) {
for(i = 1; i < data.length; i++) {
var info = data[i];
passLoc = info[6].replace('block ', '')
passLoc = passLoc.replace(/ /g, "+")
getLoc(passLoc, function(loc) {
location.push(loc);
//If I console.log(location) here I get all the info I want but.....it is printed 100 times becuase it is printed for each i in data.length
})
}
console.log(location) // loging this here gives me an empty array
}))
}else {
console.error('The address is unavailable. (%d)', res.statusCode);
}
})
}
function getLoc(x, callback) {
var url = "http://geodata.alleghenycounty.us/arcgis/rest/services/Geocoders/EAMS_Composite_Loc/GeocodeServer/findAddressCandidates?Street=" + x + "&City=Pittsburgh&State=PA&ZIP=&SingleLine=&outFields=&outSR=4326&searchExtent=&f=pjson";
http.get(url, function(res) {
var data = '';
res.on('data', function(chunk) {
data += chunk;
});
res.on('end', function() {
var d = JSON.parse(data);
var obj = d.candidates;
if(obj != '') {
var loc = obj[0].location
var lat = loc.x
var lng = loc.y
var location = [lat, lng];
callback(location)
} else {
callback(x);
}
});
res.on('error', function(err) {
callback("error!")
});
});
}
Your code tries to synchronously consume asynchronous data -- you're synchronously trying to access the results (location) before any of the asynchronous operations have finished.
As you have multiple async operations running in parallel, you can make use of async.parallel to aid in controlling the asynchronous flow:
var async = require('async');
function run() {
http.get(url, function(res) {
if(res.statusCode === 200) {
res.pipe(parse(function(err, data) {
// array of async tasks to execute
var tasks = [];
data.slice(1).forEach(function(info) {
var passLoc = info[6].replace('block ', '').replace(/ /g, '+');
// push an async operation to the `tasks` array
tasks.push(function(cb) {
getLoc(passLoc, function(loc) {
cb(null, loc);
});
});
});
// run all async tasks in parallel
async.parallel(tasks, function(err, locations) {
// consume data when all async tasks are finished
console.log(locations);
});
}));
}else {
console.error('The address is unavailable. (%d)', res.statusCode);
}
});
}
Also, for loops don't create a scope, so I've swapped it by a forEach in order to scope the info and passLoc variables inside each iteration.
Here's a slightly more condensed version using ES5's Array#map:
var async = require('async');
function run() {
http.get(url, function(res) {
if(res.statusCode === 200) {
res.pipe(parse(function(err, data) {
async.parallel(
// map data items to async tasks
data.slice(1).map(function(info) {
return function(cb) {
var passLoc = info[6].replace('block ', '').replace(/ /g, '+');
getLoc(passLoc, function(loc) {
cb(null, loc);
});
};
}),
function(err, locations) {
// consume data when all async tasks are finished
console.log(locations);
}
);
}));
} else {
console.error('The address is unavailable. (%d)', res.statusCode);
}
});
}

Categories

Resources