Resolving a deferred Q multiple times - node.js

As I know deferred can be resolved only once and also nodejs caches the required module at the first step in order to prevent loading it every single time, but what I want to do is renewing deferred Q object each time I want to resolve/reject a returned value.
This is my server code :
// server.js
app.get('/api/posts', function(req,res,next){
var insta = require('./upRunner'); // this's the main obstacle
insta.returner().then(function(data){
// ....
};
});
and the code for ./upRunner.js is :
// upRunner.js
...
var defer = Q.defer();
upRunner();
function extractor(body) {
var $ = cheerio.load(body), scripts= [];
$('script').each(function(i, elem){
scripts[i] = $(this).text();
});
var str = scripts[6],
newData = JSON.parse(str.substring(str.indexOf("{"), str.lastIndexOf(";"))).entry_data.TagPage[0].tag.media.page_info;
grabber(str);
return newData;
}
function grabber(str) {
newData = JSON.parse(str.substring(str.indexOf("{"), str.lastIndexOf(";"))).entry_data.TagPage[0].tag.top_posts.nodes;
newData.sort(dynamicSort('-date'));
newData.forEach(function(elem,index,array){
if (instaImages.length >= 10) {
defer.resolve(instaImages);
} else {
instaImages.push(elem);
}
});
}
function upRunner(newData){
profilePage = !(tagPage = URL.includes("/tags/") ? true : false);
if (!newData) {
request(URL,{jar:true}, function(err, resp, body){
var $ = cheerio.load(body), scripts= [];
$('script').each(function(i, elem){
scripts[i] = $(this).text();
});
var str = scripts[6],
newData = JSON.parse(str.substring(str.indexOf("{"), str.lastIndexOf(";"))).entry_data.TagPage[0].tag.media.page_info;
upRunner(newData);
});
} else {
if (newData.has_next_page) {
requester(URL, newData.end_cursor).then(function(body){
newData = extractor(body);
upRunner(newData);
});
} else {
console.log('it\'s finished\n');
}
function returner() {
return deferred.promise;
}
exports.returner = returner;
As you see I'm almost renewing upRunner returner deferred promise each time server get /api/posts address, but the problem is the deferred object still return the old resolved value.
There is the grabber function which resolve value, so defer can not be localized in a single function.

Try to initialized deferred value locally to get new resolve value.
function returner() {
var defer= $q.defer();
return deferred.promise;
};
exports.returner = returner;

Related

How to get the value from an api call and store it in a variable and updated a dynamodb record

I have a web request which gets some data and returns the response. I am looking to see how to store the response in a variable so it can be used later on in the code.
This is for node js running in a lambda function
/**
* Performs operations for vehicle management actions interfacing primiarly with
* Amazon DynamoDB table.
*
* #class vehicle
*/
/**
* Registers a vehicle to and owner.
* #param {JSON} ticket - authentication ticket
* #param {JSON} vehicle - vehicle object
* #param {createVehicle~callback} cb - The callback that handles the response.
*/
vehicle.prototype.createVehicle = function(ticket, vehicle, cb) {
let vehicle_data = [];
vehicle_data.push(vehicle);
let vin_data = _.pluck(vehicle_data, 'vin');
let vin_number = vin_data[0];
console.log(vin_number);
var options = {
url: 'https://vindecoder.p.mashape.com/decode_vin?' + 'vin=' + vin_number,
headers: {"X-Mashape-Key": "XXXXXXXXXXXXXXXXXXXXXXXXXX","Accept": "application/json"}
};
var data;
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
var result = JSON.parse(body);
var data = result['specification'];
//console.log(data);
}
}
request(options, callback);
var year = data['year'];
var make = data['make'];
var model = data['model'];
var trim_level = data['trim_level'];
var engine = data['engine'];
var body_style = data['style'];
var made_in = data['made_in'];
var steering_type = data['steering_type'];
var anti_brake_system = data['anti_brake_system'];
var fuel_tank = data['tank_size'];
var overall_height = data['overall_height'];
var overall_length = data['overall_length'];
var overall_width = data['overall_width'];
var standard_seating = data['standard_seating'];
var optional_seating = data['optional_seating'];
var highway_mileage = data['highway_mileage'];
var city_mileage = data['city_mileage'];
vehicle.owner_id = ticket['cognito:username'];
// vehicle.vehicle_year = year;
// vehicle.make = make;
// vehicle.model = model;
// vehicle.trim_level = trim_level;
// vehicle.engine = engine;
// vehicle.body_style = style;
// vehicle.made_in = made_in;
// vehicle.steering_type = steering_type;
// vehicle.anti_brake_system = anti_brake_system;
// vehicle.fuel_tank = fuel_tank;
// vehicle.overall_height = overall_height;
// vehicle.overall_length = overall_length;
// vehicle.overall_width = overall_width;
// vehicle.standard_seating = standard_seating;
// vehicle.optional_seating = optional_seating;
// vehicle.highway_mileage = highway_mileage;
// vehicle.city_mileage = city_mileage;
let params = {
TableName: ddbTable,
Item: vehicle
};
let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig);
docClient.put(params, function(err, data) {
if (err) {
console.log(err);
return cb(err, null);
}
return cb(null, vehicle);
});
};
I expect the response from the api call to be stored in a an object so it can be used to update the dynamodb record
There are various problems in your code. See the comments I left in the code.
Your function is failing because of the asynchronous nature of javascript. Basically, you have a request callback with a result that never gets seen by the rest of your code. Using promises and async/await is one clean way to resolve this. See below:
// use request promise instead of request
// promises will make your life much easier
// https://hackernoon.com/javascript-promises-and-why-async-await-wins-the-battle-4fc9d15d509f
// https://github.com/request/request-promise
const request = require('request-promise')
vehicle.prototype.createVehicle = function(ticket, vehicle, cb) {
// No need to use var anymore with es6, just use let and const
// https://www.sitepoint.com/es6-let-const/
let vehicle_data = [];
vehicle_data.push(vehicle);
let vin_data = _.pluck(vehicle_data, "vin");
let vin_number = vin_data[0];
console.log(vin_number);
const options = {
uri: "https://vindecoder.p.mashape.com/decode_vin?" + "vin=" + vin_number,
headers: {
"X-Mashape-Key": "XXXXXXXXXXXXXXXXXXXXXXXXXX",
Accept: "application/json"
}
};
// Here's the main mistake
// request has a callback function that is asynchronous
// the rest of your code never sees the result because the result doesn't leave the callback
// your code continues to execute without waiting for the result (this is the gist of asynchronity in js)
// function callback(error, response, body) {
// if (!error && response.statusCode == 200) {
// const result = JSON.parse(body);
// const data = result["specification"]; // this variable doesn't leave the scope of this callback
// //console.log(data);
// }
// }
// therefore this is the failure point
// request(options, callback);
// Do this instead
// here I utilize promises and async/ await
// https://medium.com/codebuddies/getting-to-know-asynchronous-javascript-callbacks-promises-and-async-await-17e0673281ee
try {
const result = await request(options);
const data = result["specification"];
} catch (error) {
console.log(error);
}
// Now data is available to be used below in dynamodb
// also, utilize objects, its much cleaner
const carVariables = {
year: data["year"],
make: data["make"],
model: data["model"],
trim_level: data["trim_level"],
engine: data["engine"],
body_style: data["style"],
made_in: data["made_in"],
steering_type: data["steering_type"],
anti_brake_system: data["anti_brake_system"],
fuel_tank: data["tank_size"],
overall_height: data["overall_height"],
overall_length: data["overall_length"],
overall_width: data["overall_width"],
standard_seating: data["standard_seating"],
optional_seating: data["optional_seating"],
highway_mileage: data["highway_mileage"],
city_mileage: data["city_mileage"],
};
vehicle.owner_id = ticket["cognito:username"];
vehicle = { ...vehicle, ...carVariables} // ES6 spread operator does the below code for you:
// one line versus 20. win. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
// vehicle.vehicle_year = year;
// vehicle.make = make;
// vehicle.model = model;
// vehicle.trim_level = trim_level;
// vehicle.engine = engine;
// vehicle.body_style = style;
// vehicle.made_in = made_in;
// vehicle.steering_type = steering_type;
// vehicle.anti_brake_system = anti_brake_system;
// vehicle.fuel_tank = fuel_tank;
// vehicle.overall_height = overall_height;
// vehicle.overall_length = overall_length;
// vehicle.overall_width = overall_width;
// vehicle.standard_seating = standard_seating;
// vehicle.optional_seating = optional_seating;
// vehicle.highway_mileage = highway_mileage;
// vehicle.city_mileage = city_mileage;
let params = {
TableName: ddbTable,
Item: vehicle
};
// This will now probably work. yay!
let docClient = new AWS.DynamoDB.DocumentClient(dynamoConfig);
docClient.put(params, function(err, data) {
if (err) {
console.log(err);
return cb(err, null);
}
return cb(null, vehicle);
});
};
This is untested but I believe it should work. And there may some typos or whatever but the main takeaway here is the use of promises and async/await to wait for and expose the result from the request. See the links and references in the comments for further reading.

Get data from nested foreach

I'm building an app using firebase and Node.js. I need to get data from nested foreach. How to do it correctly? Need to return the results of all iterations simultaneously.
exports.userParty = function (userInfo, cb) {
var userID = userInfo.userID;
var clubID = userInfo.clubID;
var refUserParty = ref.child(userID).child('my_party_id');
var party = {};
refUserParty.orderByValue().once("value", function (snapshot) {
var party = {};
snapshot.forEach(function (partyID) {
var refParty = dbb.ref('clubs').child(clubID).child('party').child(partyID.val());
refParty.once('value', function (partyBody) {
party[partyID.val()] = partyBody.val();
//console.log(party);
});
});
cb(party); // {}
});
};
You need to call the callback after all the async functions in the forEach block have completed. You can do this using a simple counter to check all async functions are complete:
...
let completedSnapshots = 0;
snapshot.forEach(function (partyID) {
var refParty = dbb.ref('clubs').child(clubID).child('party').child(partyID.val());
refParty.once('value', function (partyBody) {
party[partyID.val()] = partyBody.val();
completedSnapshots++;
if (completedSnapshots === snapshot.val().length) {
cb(party);
}
});
});
...

How can i write a mocha test for the following function?

I want to write a test for this node.js funcion,This has two arguments request and response. I set the request variable . But dont know how to set response variable.
function addCustomerData(request, response) {
common.getCustomerByMobile(request.param('mobile_phone'), function (customerdata) {
if (!customerdata) {
var areaInterest = request.param('area_interest');
var customerInfo = {userType: request.param('userType'),
firstName : request.param('first_name'),
middleName : request.param('middle_name'),
lastName : request.param('last_name'),
email : request.param('email'),
mobilePhone : request.param('mobile_phone'),
uniqueName : request.param('user_name'),
company : request.param('company')
};
if(customerInfo.email){
customerInfo.email = customerInfo.email.toLowerCase();
}
if(customerInfo.uniqueName){
customerInfo.uniqueName = customerInfo.uniqueName.toLowerCase();
}
if(areaInterest) {
customerInfo.areaInterest = '{' + areaInterest + '}';
}else
areaInterest = null;
addCustomer(request, response, customerInfo, function (data) {
request.session.userId = data;
return response.send({success: true, message: 'Inserted successfully'});
}
);
} else {
return response.send({success: false, message: 'User with this mobile number already exists'});
}
});
}
I wrote the test as follows
describe('signup', function(){
describe('#addCustomer()', function(){
before(function (done) {
request = {};
request.data = {};
request.session = {};
request.data['userType'] = '3';
request.data['first_name'] = 'Shiji';
request.data['middle_name'] = '';
request.data['last_name'] = 'George';
request.data['email'] = 'shiji#lastplot.com';
request.data['mobile_phone'] = '5544332333';
request.data['user_name'] = 'shiji';
request.session['imageArray'] = [];
request.param=function(key){
// Look up key in data
return this.data[key];
};
request1 = {};
request1.data = {};
request1.session = {};
request1.data['area_interest']=["aluva","ernakulam"];
request1.data['userType'] = '1';
request1.data['first_name'] = 'Hari';
request1.data['middle_name'] = 'G';
request1.data['last_name'] = 'Ganesh';
request1.data['email'] = 'hari#lastplot.com';
request1.data['mobile_phone'] = '5544332321';
request1.data['user_name'] = 'hariganesh';
request1.data['company'] = 'HG Realestate';
request1.session['imageArray'] = [];
request1.param=function(key){
// Look up key in data
return this.data[key];
};
done();
});
it('It should list the matching properties', function(done){
async.parallel([
function(callback) {
signup.addCustomerData(request, response, function (result, err) {
should.not.exist(err);
should.exists(result);
callback();
});
},
function(callback) {
signup.addCustomerData(request1, response, function (result, err) {
should.not.exist(err);
should.exists(result);
callback();
});
}],function(){
done();
});
});
But i got the error as response has no method send()
Thanks in Advance.
Your addCustomerData function does not have a callback, it just calls respond.send(). You need to mock the response object, as well as the send method, and put your tests inside of it, but you won't be able to use async.parallel() as, like I already mentioned, your function does not have a callback parameter. If you're testing request/response functions, I suggest you look into Supertest https://github.com/visionmedia/supertest which is widely used for cases like this.

RequireJS : Missing file gives error for first time but results in request timeout for further requests until server is restarted

I'm using RequireJS for loading modules but if one unavailable file is required, it gives error for first request but skips errors for successive requests and result in request timeout.
A sample of code I'm using :
var requireJS = require("requirejs");
var Q = require("q");
var fxndef = "some-test-function-definition";
function test1(){
var d = Q.defer();
requireJS([fxndef.source], function (requireModule) {
if (!requireModule) {
d.reject(new Error("Function not found for[" + JSON.stringify(fxndef) + "]"));
return;
}
var loadedFunction = requireModule[fxndef.name];
if (loadedFunction) {
d.resolve(loadedFunction);
} else {
d.reject(new Error("Function not found for[" + JSON.stringify(fxndef.name) + "]"));
}
});
requireJS.onError = function (err) {
console.log("In Error......")
d.reject(err);
};
}
test1();
test1();
The above code snippet receives a error for one time only and not twice as expected.
What am i missing ?
I'm not an expert on requirejs, but this may not be a requirejs issue. I think you are missing the second error because your code is completing before the asynchronous operation is done for the second method call. Try running this slightly modified code (note that we are returning d.promise, and handing the results to console.log):
var requireJS = require("requirejs");
var Q = require("q");
var fxndef = "some-test-function-definition";
function test1(){
var d = Q.defer();
requireJS([fxndef.source], function (requireModule) {
if (!requireModule) {
d.reject(new Error("Function not found for[" + JSON.stringify(fxndef) + "]"));
return;
}
var loadedFunction = requireModule[fxndef.name];
if (loadedFunction) {
d.resolve(loadedFunction);
} else {
d.reject(new Error("Function not found for[" + JSON.stringify(fxndef.name) + "]"));
}
});
requireJS.onError = function (err) {
console.log("In Error......")
d.reject(err);
};
return d.promise;
}
test1().done(console.log, console.log)
test1().done(console.log, console.log)

mongodb data async in a for-loop with callbacks?

Here is a sample of the working async code without mongodb. The problem is, if i replace the vars (data1_nodb,...) with the db.collection.find(); function, all needed db vars received at the end and the for()-loop ends not correct. Hope someone can help. OA
var calc = new Array();
function mach1(callback){
error_buy = 0;
// some vars
for(var x_c99 = 0; x_c99 < array_temp_check0.length;x_c99++){
// some vars
calc[x_c99] = new Array();
calc[x_c99][0]= new Array();
calc[x_c99][0][0] = "dummy1";
calc[x_c99][0][1] = "dummy2";
calc[x_c99][0][2] = "dummy3";
calc[x_c99][0][3] = "dummy4";
calc[x_c99][0][4] = "dummy5";
function start_query(callback) {
data1_nodb = "data1";
data2_nodb = "data2";
data3_nodb = "data3";
data4_nodb = "data4";
calc[x_c99][0][0] = data1_nodb;
calc[x_c99][0][1] = data2_nodb;
calc[x_c99][0][2] = data3_nodb;
callback(data1_nodb,data2_nodb,etc..);
}
start_query(function() {
console.log("start_query OK!");
function start_query2(callback) {
data4_nodb = "data5";
data5_nodb = "data6";
data6_nodb = "data7";
calc[x_c99][0][3] = data4_nodb;
calc[x_c99][0][4] = data5_nodb;
callback(data5_nodb,data6_nodb,etc..);
}
start_query2(function() {
console.log("start_query2 OK!");
function start_query3(callback) {
for(...){
// do something
}
callback(vars...);
}
start_query3(function() {
console.log("start_query3 OK!");
});
});
});
}
callback(calc);
};
function mach2(callback){
mach1(function() {
console.log("mach1 OK!");
for(...){
// do something
}
});
callback(calc,error_buy);
};
mach2(function() {
console.log("mach2 OK 2!");
});
You need to work with the async nature of the collection.find() method and wait for all of them to be done. A very popular approach is to use the async module. This module allows you run several parallel tasks and wait for them to finish with its async.parallel() method:
async.parallel([
function (callback) {
db.foo.find({}, callback);
},
function (callback) {
db.bar.find({}, callback);
},
function (callback) {
db.baz.find({}, callback);
}
], function (err, results) {
// results[0] is the result of the first query, etc
});

Resources