calling websocket send function from within .then() in nodejs - node.js

i have a promise that resolves a JSON object with some config data. i want to access this data upon pressing the "send config" button in my HTML client. the communication is done through a websocket connection in nodejs. so the websocket server receives a message that says "send config" from the client and the server is supposed to respond with the config.
code:
showMsg = function (MSGOBJ) {
var parsedOBJ = JSON.parse(MSGOBJ);
//console.log(parsedOBJ.content);
for (var i = 0; i < connections.length; i++) {
switch(parsedOBJ.type) {
case "text":
console.log("Received: " + parsedOBJ.content)
connections[i].sendUTF('{ "type":"text", "content":"Server ready."}')
break;
case "config":
console.log("Received:1 " + parsedOBJ.content)
console.log("Sending config" )
var getConfig = KRequests.getKConfig;
var configOBJ;
getConfig.then(function(result) {
configOBJ = result
});
connections[i].send('{ "type":"config", "content":'+JSON.stringify(configOBJ)+'}');
break;
}
}
}
i know configOBJ would be undefined if i use it outside of the chain, but just to give you an idea of what i want to do. and also if i move the send() inside the chain, it would cause this error: "UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'send' of undefined"

You have two issue one is that you should use:
getConfig.then(function(result) {
console.log(connections[i])
connections[i].send('{ "type":"config", "content":'+JSON.stringify(configOBJ)+'}');
});
The other is that:
for (var i = 0; i < connections.length; i++) {
should be:
for (let i = 0; i < connections.length; i++) {
Or if you don't have let which you should if you are using a recent node that supports more than ES5. You will have to use a IIFE like this:
for (var i = 0; i < connections.length; i++) {
(function (i) {
// put the loop body here
})(i);
}

Related

Parallel processing fails in node js

I have the below piece of code which hits a url for each user id in loop.
var requests = [];
for (let i = 0; i < userids.length; i++) {
requests.push(this.getUserData(authToken, userid[i]));
}
const userdetails=await (Promise as any).allSettled(requests);
The code fails for some requests and returns error for some requests. But when the same code is implememnted using sequential processing it works and returns correct data. Below is the code for the same
var requests:any=[]
for (let i = 0; i < userids.length; i++) {
requests.push(await this.getUserData(authToken, userid[i]));
}
How shall I fix it?

How can I get the original request URL in the response callback?

I have a loop like this:
var req;
for (var i=0; i<sites.length; i++) {
req = https.get(sites[i], handleRequest);
req.on('error', handleError);
}
The callback (handleRequest) runs asynchronously, for each website being requested.
However, the only parameter in handleRequest seems to be a "response".
When the callback is run, the loop has already completed, so how can I keep track of which website is this response for, so I can handle it accordingly?
You can change your handleRequest to take two parameters - url being the first of them. With that you can partially apply the function via Function#bind and so set the url parameter at the time of calling but you'll still wait for the second argument.
let sites = [
"https://example.com",
"https://example.net",
"https://example.org"
];
function handleRequest(url, res) {
console.log("handling:", url);
/* handling code */
}
//minimalistic dummy HTTP module that responds after 1 second
let https = {
get: handler => setTimeout(handler, 1000)
}
for (var i=0; i < sites.length; i++) {
let url = sites[i];
https.get(handleRequest.bind(this, url)) //partially apply handleRequest
}
You can get a similar result via currying - instead of having two parameters, first take one, then return a function that takes the other. It leads to (in my opinion) better syntax when calling:
let sites = [
"https://example.com",
"https://example.net",
"https://example.org"
];
function handleRequest(url) {
return function actualHandler(res) {
console.log("handling:", url);
/* handling code */
}
}
//minimalistic dummy HTTP module that responds after 1 second
let https = {
get: handler => setTimeout(handler, 1000)
}
for (var i=0; i < sites.length; i++) {
let url = sites[i];
https.get(handleRequest(url))
}

synchronous execution of methods

I have below snmp call in my code, and am executing this in api call and need to get array of values and return it to the client side. but i am facing issue in executing this lines synchronously, my res.json executing first before getting vales from session.subtree
var shelf = new Array();
function doneCb (error) {
console.log("donecb");
console.log("shelf -----",shelf);
}
function feedCb (varbinds) {
console.log("feed cb");
shelf = [];
for (var i = 0; i < varbinds.length; i++) {
if (snmp.isVarbindError (varbinds[i]))
console.error (snmp.varbindError (varbinds[i]));
else {
var temp = varbinds[i].oid.trim(".");
shelf.push({'id':temp[temp.length-1], 'name':shelfmap[varbinds[i].value.toString()]});
console.log (varbinds[i].oid + "|" + shelfmap[varbinds[i].value.toString()]);
}
}
}
router.get('/getShelves/:r',function(req,res){
shelf = [];
session.subtree (oid, maxRepetitions, feedCb, doneCb);
res.json(shelf);
});
since feedcb and donecb are internal methods of net-snmp module i am not able to rewrite the functions to return the values, I tried with sync and async waterfall model, but it is not working as excepted, kinldy someone suggest some way to execute the method synchronously in node JS. Thanks in advance.

Modellinng in node js

I have scenario in node api where its receives response from another API and i have to concatenate 2 fields from response and send response for my api.
e.g. Response from another API:
[{"fname":"mark","lname":"Bradd"},
{""fname":"Jordon","lname":"Gibb""} ]
Concatenated Response:
{"fname":"mark","lname":"Bradd","fullname":"mark Bradd"},
{"fname":"Jordon","lname":"Gibb","fullname" :"Jordon Gibb"}
I can loop through response which I am getting but I am not sure how can I create response with concatenated fields.
for(var i = 0; i < recv.length; i++)
{
var sm=recv[i].fName+ " " + recv[i].lName;
var person= person.PersonFullName(sm);
}
//person model code
var PersonFullName = function (data) {
this.push(data)
}
module.exports = PersonFullName;
I was trying to create another object with model but couldn't get success. Can you please let me know how can I achieve this in node.
You can try the following code:
var concatenatedResponse = [];
for(var i = 0; i < recv.length; i++){
concatenatedResponse.push({"fname" : recv[i].fName, "lname" : recv[i].lName, "fullname" : recv[i].fName + " " + recv[i].lName);
}

handling asynchronous call backs in nodejs

I am newbie to nodejs.It's very hard to handle callbacks at nodejs level. I have code like this,
getItems(request,function(jsonObject){
var itemData={};
var itemDetails=new Array();
for(var i=0;i < jsonObject.length;i++){
getItemDetails(jsonObject[i].value.item_id,function(jsonObject){
itemDetails.push(jsonObject);
});
}
itemData["itemDetails"]=itemDetails;
response.contentType("application/json");
response.send({"data":itemData});
});
while executing the above code, the for loop is continuing with out getting callback from getItemDetails method and response sent to client. My requirement is the loop will wait until getting the call back from the getItemDetails then response should send.
I have tried with process.nextTick(), but i am unable to find where i have to use that process.nextTick().. Please anybody provide suggestions.
Thanks in advance.
You need to send the response only after you get all the items, so modify your code like so:
getItems(request,function(jsonObject) {
var itemData = {},
itemDetails = [],
itemsLeft = len = jsonObject.length,
i;
function sendResponse(itemDetails) {
itemData["itemDetails"] = itemDetails;
response.contentType("application/json");
response.send({ "data": itemData });
}
for (i = 0; i < len; i++) {
getItemDetails(jsonObject[i].value.item_id, function(jsonObject) {
itemDetails.push(jsonObject);
// send response after all callbacks have been executed
if (!--itemsLeft) {
sendResponse(itemDetails);
}
});
}
});
Note: I've used itemLeft here since it's a more generic way to solve these kind of problems, but Ianzz approach is also ok since you can compare the length of the two arrays.
You can't get the loop to wait, but you can modify your code to get the behavior you are expecting:
getItems(request,function(outerJsonObject){
var itemData={};
var itemDetails=new Array();
for(var i=0;i < outerJsonObject.length;i++){
getItemDetails(jsonObject[i].value.item_id,function(innerJsonObject){
itemDetails.push(innerJsonObject);
if (itemDetails.length == outerJsonObject.length) {
// got all item details
itemData["itemDetails"]=itemDetails;
response.contentType("application/json");
response.send({"data":itemData});
}
});
}
});

Resources