Nodejs loop through same API with different parameters - node.js

I trying to loop through same API result and if the API result is NULL then I want loop through it again few times (i.e 4-5 times) with different parameters and if it's reached the 5th time. I want to exit the loop. The code I'm trying is see below:
var roads = 1000;
var findResult = true;
var loop = 0;
while (findResult) {
result = APIResult(rarray, roads);
if (result !== null) {
findResult = false; // stop the loop
} else if (loop == 5) {
findResult = false; // stop the loop
} else {
roads = roads * 10;
loop++;
}
}
function APIResult(rarray, roads) {
request.post(
env.TEST_URL + 'test/',
{
json: {
//...
roads: roads,
//..
},
},
function(error, response, body) {
if (!error && response.statusCode == 200) {
return JSON.parse(body.rows[0].result);
}
});
}
I'm even tried adding Q promise but didn't worked, any idea how to do it?

Your APIResult function doesn't return anything. This function is asynchronous, so it should return promise or use a callback.
Your code result = APIResult(rarray, roads); sets to result variable undefined value. I think, async/await style for implementing asynchronous JS features will work for you.
Current last Node.js version is 8.1. It has native support for async/await. There is an example, how you can implement your code:
async function main() {
var roads = 1000;
var findResult = true;
var loop = 0;
while (findResult) {
try {
result = await APIResult(rarray, roads);
} catch (e) {
//APIResult reject promise branch
}
if (result !== null) {
findResult = false; // stop the loop
} else if (loop == 5) {
findResult = false; // stop the loop
} else {
roads = roads * 10;
loop++;
}
}
}
async function APIResult(rarray, roads) {
return new Promise((res, rej) => {
request.post(
env.TEST_URL + 'test/',
{
json: {
//...
roads: roads,
//..
},
},
function(error, response, body) {
if (error) return rej(error);
if (response.statusCode === 200) return res(JSON.parse(body.rows[0].result));
});
});
}
main();

Related

NodeJS Async/Await or Promise for net-snmp module

please someone help, I just cant get it.
Can you please help on how to make async/await or promise (doneCb), so script waits for first vlc_snmp(..) to finish and then to call next?
Example:
function doneCb(error) {
console.log(final_result);
final_result = [];
if (error)
console.error(error.toString());
}
function feedCb(varbinds) {
for (var i = 0; i < varbinds.length; i++) {
if (snmp.isVarbindError(varbinds[i]))
console.error(snmp.varbindError(varbinds[i]));
else {
var snmp_rez = {
oid: (varbinds[i].oid).toString()
value: (varbinds[i].value).toString()
};
final_result.push(snmp_rez);
}
}
}
var session = snmp.createSession(VLC_IP, "public", options);
var maxRepetitions = 20;
function vlc_snmp(OID) {
session.subtree(OID_, maxRepetitions, feedCb, doneCb);
}
vlc_snmp(OID_SERIAL_NUMBER);
//wait OID_SERIAL_NUMBER to finish and then call next
vlc_snmp(OID_DEVICE_NAME);
You should be able to use the async / await statements to wait for your done callback to be called. We wrap this callback in the vlc_snmp function, and return a Promise. This allows us to use the await statement.
I've mocked out some of the code that I don't have access to, it should behave somewhat similarly to the real code.
The key point here is, when a function returns a Promise we can await the result in an async function, that will give you the behaviour you wish.
final_result = [];
const VLC_IP = "";
const options = {};
const OID_ = "OID_";
const OID_SERIAL_NUMBER = "OID_SERIAL_NUMBER"
const OID_DEVICE_NAME = "OID_DEVICE_NAME"
// Mock out snmp to call feedcb and donecb
const snmp = {
createSession(...args) {
return {
subtree(oid, maxRepetitions, feedCb, doneCb) {
setTimeout(feedCb, 500, [{ oid, value: 42}])
setTimeout(doneCb, 1000);
}
}
},
isVarbindError(input) {
return false;
}
}
function doneCb(error) {
console.log("doneCb: final_result:", final_result);
final_result = [];
if (error)
console.error("doneCb: Error:", error.toString());
}
function feedCb(varbinds) {
for (var i = 0; i < varbinds.length; i++) {
if (snmp.isVarbindError(varbinds[i]))
console.error(snmp.varbindError(varbinds[i]));
else {
var snmp_rez = {
oid: (varbinds[i].oid).toString(),
value: (varbinds[i].value).toString()
};
final_result.push(snmp_rez);
}
}
}
var session = snmp.createSession(VLC_IP, "public", options);
var maxRepetitions = 20;
function vlc_snmp(OID) {
return new Promise((resolve,reject) => {
session.subtree(OID, maxRepetitions, feedCb, (error) => {
// This is a wrapper callback on doneCb
// Always call the doneCb
doneCb(error);
if (error) {
reject(error);
} else {
resolve();
}
});
});
}
async function run_vls_snmp() {
console.log("run_vls_snmp: Calling vlc_snmp(OID_SERIAL_NUMBER)...");
await vlc_snmp(OID_SERIAL_NUMBER);
console.log("run_vls_snmp: Calling vlc_snmp(OID_DEVICE_NAME)...");
//wait OID_SERIAL_NUMBER to finish and then call next
await vlc_snmp(OID_DEVICE_NAME);
}
run_vls_snmp();

How to get code to execute in order in node.js

I am trying to finish my script, but for some reason i don't know, it refuses to execute in the order i put it in.
I've tried placing a 'wait' function between the JoinRequest update function and the following code, but when run, it acts as if the function call and wait function were the other way round, countering the point of the wait().
const Roblox = require('noblox.js')
var fs = require('fs');
var joinRequests = []
...
function wait(ms) {
var d = new Date();
var d2 = null;
do { d2 = new Date(); }
while(d2-d < ms*1000);
};
...
function updateJReqs() {
Roblox.getJoinRequests(4745601).then((array) => {
var i;
var final = [];
for(i = 0; i < array.length; i++) {
final.push(array[i].username);
};
if(final === '') {
final = '-None';
};
joinRequests = final
console.log('Updated join requests.')
});
}
function check() {
setTimeout(() => {
fs.readFile('Request.txt',encoding = 'utf-8', function(err, data) {
if (err) {
check();
} else {
updateJReqs(); //for some reason this function is executed alongside the below, not before it.
// Tried putting wait(x) in here.
console.log('Request received: ' + data)
var solution = joinRequests
console.log('Fuffiling request with ' + solution)
fufillRequest(solution)
fs.unlink('Request.txt', function(err) {
if(err) throw err;
});
check();
}
});
}, 400)
}
check();
The script is supposed to wait until a file is created (accomplished), update the list of join requests (accomplished) and then create a new file with the list of join requests in(not accomplished).
if I understand your code you work with async code, you need to return a promise in updateJReqs and add a condition of leaving from the function because you have an infinite recursion
function updateJReqs() {
return new Promise(resolve => {
Roblox.getJoinRequests(4745601).then((array) => {
var i;
var final = [];
for(i = 0; i < array.length; i++) {
final.push(array[i].username);
};
if(final === '') {
final = '-None';
};
joinRequests = final
console.log('Updated join requests.')
resolve();
});
}
}
async function check() {
setTimeout(() => {
fs.readFile('Request.txt',encoding = 'utf-8', function(err, data) {
if (err) {
await check();
} else {
await updateJReqs();
// Tried putting wait(x) in here.
console.log('Request received: ' + data)
var solution = joinRequests
console.log('Fuffiling request with ' + solution)
fufillRequest(solution)
fs.unlink('Request.txt', function(err) {
if(err) throw err;
});
// you dont have an exit from your function check();
return 'Success';
}
});
}, 400)
}
check().then(res => console.log(res));

My two variables are not equal sometimes but must be

My two variable "soundTypeFound[0].name" and "req.soundTypes[iteration]" must be the same everytime but once in five times its coming as false.
I think the loop goes more quickly than the function "allSoundTypeQuery.GetSoundTypeByName(item, (soundTypeFound, err) => {}" and the variable "iteration" does not have the time to be incremented as same time as the loop.
Thank you for your help
async function checkSoundTypes (req, res, soundTypesString, error, next) {
let stop = false;
req.soundTypes = soundTypesString.split(',');
let iteration = 0;
for (let item of req.soundTypes) {
await allSoundTypeQuery.GetSoundTypeByName(item, (soundTypeFound, err) => {
if (err) {
return res.status(500).json({"error": "Cannot find the sound type in the DB"});
}
if (soundTypeFound.length <= 0 || soundTypeFound[0].name !== req.soundTypes[iteration]) {
stop = true;
}
iteration++;
if (iteration === req.soundTypes.length) {
if (stop === true) {
error.push("soundTypes");
return res.status(400).json(error);
}else if (err) {
return res.status(400).json(error);
}else {
next();
}
}
});
}
}
Since you were sending a callback function, it will not wait and move forward with the next iteration, so it causing error,now the method will return promise as we are using promisify method of the util module, not it will wait for the promise to resolve and then move to the next line.
const {promisify} = require('util');
async function checkSoundTypes (req, res, soundTypesString, error, next) {
let stop = false;
req.soundTypes = soundTypesString.split(',');
let iteration = 0;
for (let item of req.soundTypes) {
const getSoundTypeByName = promisify(allSoundTypeQuery.GetSoundTypeByName);
const soundTypeFound= await getSoundTypeByName(item);
if (!soundTypeFound) { // this you should check as per your response
return res.status(500).json({"error": "Cannot find the sound type in the DB"});
}
if (soundTypeFound.length <= 0 || soundTypeFound[0].name !== req.soundTypes[iteration]) {
stop = true;
}
iteration++;
if (iteration === req.soundTypes.length) {
if (stop === true) {
error.push("soundTypes");
return res.status(400).json(error);
}else if (err) {
return res.status(400).json(error);
}else {
next();
}
}
}
}

node.js - using .map to enrich object

I have an object (set of product data), within some of those objects I have an array of images. For each of the images I need to call an API to get extra data, then I want to put this back into the original object.
The API call is by ID, that's working and I can get the data.
I think I have a problem with the async nature and I am missing something (probably obvious!)...
Thanks!
function fetchImages(products) {
var deferred = Q.defer();
var product_updates = [];
products.forEach(function (product, idx, array) {
var image_updates = [];
if (product.images.length > 0)
{
//var id = product.images.mediaId;
//console.log(id);
image_updates = product.images.map(function(task) {
return {
image_urls: getImage(task.mediaId)
}
});
console.log(image_updates);
product_updates.push(image_updates);
}
else
{
product_updates.push(product);
}
if (idx === array.length - 1)
{
//console.log(stock_updates);
deferred.resolve(product_updates);
}
});
return deferred.promise;
}
Here is the shortened "getImage" function...
function getImage(id)
{
// Request options
var options = {
url: cfg.base_url + (cfg.base_url[cfg.base_url.length - 1] != '/' ? '/' : '') + 'api/media/' + id,
.........
};
request(options, function (error, response, body) {
// Check status code
if (response.statusCode >= 200 && response.statusCode <= 299) {
let result = JSON.parse(body);
console.log(result);
return result;
} else {
console.log("Failed to fetch images updates");
}
}
);
}
I'm also unsure if "deferred.resolve(product_updates);" is done correctly.. seems to work but not 100% sure.
console.log for "image_update" returns:
[ { image_urls: undefined },
{ image_urls: undefined },
{ image_urls: undefined },
{ image_urls: undefined },
{ image_urls: undefined } ]
************ Amended fetchImages() function ***********
function fetchImages(products) {
const getImagesForProduct = function(product) {
return product.images.map(function(task) {
return {
product: product,
image_urls: getImage(task.mediaId)
}
});
}
const product_updates = products.map(getImagesForProduct)
return new Promise(function(resolve, reject)
{
resolve(product_updates);
});
}
This is more eloquent now... but still not got the promise needed?
In you example getImage makes and asynchronous call and therefore should return a promise. Many ways to return a promise - but the native promise object is the easiest (i suspect you could do this with Q too - but it has been a long time since I used that library).
function getImage(id)
{
// Request options
var options = {
url: cfg.base_url + (cfg.base_url[cfg.base_url.length - 1] != '/' ? '/' : '') + 'api/media/' + id,
.........
};
return new Promise(function(resolve, reject){
request(options, function (error, response, body) {
// Check status code
if (response.statusCode >= 200 && response.statusCode <= 299) {
let result = JSON.parse(body);
console.log(result);
resolve(result);
} else {
reject(error);
}
});
})
}
The other function could be written more eloquently too. Essentially:
// :: Product -> [{image_urls: Promise}]
const getImagesForProduct = function(product) {
return product.images.map(function(task) {
return {
image_urls: getImage(task.mediaId)
}
});
}
const product_updates = products.map(getImagesForProduct)
//=> [[{image_urls: Promise}]]
In this scenario you still need to wait on the promises to resolve. I suspect you could flatten the array or restructure the transformations to be less hairy - but it depends on what your other code needs
Here's the final function that deals with the promises:
function fetchImages(products) {
const getImagesForProduct = function(product) {
if (product.images && product.images.length === 0) {
return Promise.resolve(product)
}
const getImagesPromiseTasks = product.images.map(task => getImage(task.mediaId));
return Promise.all(getImagesPromiseTasks)
.then(retrievedUrls => {
product.image_urls = retrievedUrls
return product
})
}
return Promise.all(products.map(getImagesForProduct))
}

How can I write sequential execution in foreach loop of nodejs?

I am new to nodejs. please help me how to save the data in foreach loop and send response back to controller.it returns false not return object. Thanks in advance
Here is my code like
var rideStatus = require('../models/ridestatus');
module.exports = {
invite_ride: function* (body) {
var saved = false;
var receivers = body.uids;
receivers = receivers.split(',').filter(function(n) { return n != 'null'; });
receivers.forEach(function* (n) {
yield rideStatus.findOne(
{$and: [{ride_id: body.rideid}, {receiver_id: receivers}]},
function(err, doc) {
if (doc === null) {
new rideStatus({
ride_id: body.rideid,
invited_id: body.userId,
receiver_id: receivers,
}).save(function(err1, ridestatus) {
if (!err1) {
rideStatus.findOne({_id: ridestatus._id}).
populate('ride_id').
populate('invited_id').
populate('receiver_id').
exec(function(err2, user) {
// console.log(user);
if (user != null) {
saved = user;
}
});
}
});
}
});
});
return saved;
},
};
because of the asynchronous nature of node.js your "return save" statement won't wait for your i/o to complete his work. and also note that if you have multiple values to be saved, you should return an array of saved Users objects.
var rideStatus = require('../models/ridestatus');
module.exports = {
invite_ride: function* (body) {
var savedUsers = [];
var receivers = body.uids;
receivers = receivers.split(',').filter(function(n) { return n != 'null'; });
var len = receivers.length
var i=0
receivers.forEach(function* (n) {
yield rideStatus.findOne(
{$and: [{ride_id: body.rideid}, {receiver_id: receivers}]},
function(err, doc) {
if (doc === null) {
new rideStatus({
ride_id: body.rideid,
invited_id: body.userId,
receiver_id: receivers,
}).save(function(err1, ridestatus) {
if (!err1) {
rideStatus.findOne({_id: ridestatus._id}).
populate('ride_id').
populate('invited_id').
populate('receiver_id').
exec(function(err2, user) {
// console.log(user);
if (user != null) {
savedUsers.push(user);
}
if(i==len-1)
return savedUsers;
else
i++
});
}else{
i++
}
});
}else{
i++
}
});
});
},
};
Look at library on the link: async

Resources