Node JS Returning Without Promise Fulfilling - javascript

I am hoping this is an easy questions, and I just missed something simple. I have a chain of promise returning functions that flow using .then(). My final function takes the data I return, and formats into the correct format, which is then passed back to the client. The issue I am having (I think), is that the server sends the ff variable to the client before the promise from the formatting function is getting resolved. What confuses me, is that when I log the ff variable, it is logging with all the data as expected.
Any thoughts on why this is occurring, what I am doing wrong, and most importantly how to resolve this?
app.get("/subData", function(req, res) {
getConnection().then(function() {
return getSQL();
}).then(function(sql) {
return executeQuery(sql);
}).then(function(data) {
return formatData(data);
}).then(function(ff) {
console.log(ff);
res.status(200).send(ff);
}).catch(function(err) {
console.log("ERR:");
console.log(err);
res.status(405).send(err);
});
});
Here is the final format data function:
function formatData(data) {
var finArr = Array();
return new Promise(function(resolve, reject) {
data.rows.forEach(function(row, fin) {
var tempArr = Array();
row.forEach(function(itm, pos) {
var ttl = data.metaData[pos].name;
var val = itm;
tempArr[ttl] = val;
});
finArr.push(tempArr);
if(fin + 1 == data.rows.length) {
resolve(finArr);
}
});
});
}

It's pretty clear that one of your promises isn't resolving. Why make the resolve() call in your formatData() method conditional? Why not just let the loop run out?
function formatData(data) {
var finArr = Array();
return new Promise(function(resolve, reject) {
data.rows.forEach(function(row, fin) {
var tempArr = Array();
row.forEach(function(itm, pos) {
var ttl = data.metaData[pos].name;
var val = itm;
tempArr[ttl] = val;
});
finArr.push(tempArr);
});
resolve (finArr);
});
}
Indeed, you don't need a Promise here at all, because it's a synchronous operation. And, it's OK to use synchronous operations in .next() chains. Like this.
function formatData(data) {
var finArr = Array();
data.rows.forEach(function(row, fin) {
var tempArr = Array();
row.forEach(function(itm, pos) {
var ttl = data.metaData[pos].name;
var val = itm;
tempArr[ttl] = val;
});
finArr.push(tempArr);
});
return finArr;
}

The issue had nothing to do with promises resolving properly. The issue was in how I was formatting my data to be sent back to the client. I was building an array of associative arrays with the following code. When it was sent to the client, it was being sent as a blank array of arrays.
data.rows.forEach(function(row, fin) {
var tempArr = Array();
row.forEach(function(itm, pos) {
var ttl = data.metaData[pos].name;
var val = itm;
tempArr[ttl] = val;
});
finArr.push(tempArr);
});
return finArr;
What I needed to do was send the data as an array of objects and then convert it to an array of arrays on the client side. By adjusting my code to this, the data properly passed over as I needed.
data.rows.forEach(function(row, fin) {
// Change From var tempArr = Array() to var tempArr = {} to initialize new Object
var tempArr = {};
row.forEach(function(itm, pos) {
var ttl = data.metaData[pos].name;
var val = itm;
tempArr[ttl] = val;
});
finArr.push(tempArr);
});
return finArr;

Related

array.push(item) in function

I want to push all volume to arrayVolume but can't.
In my opinion the problem is asynchronous. But I search, read document but can't do it run correct.
Please help me solve the code if you can.
That is my gratitude to you.
Many thanks!
function kl(data){
var arrayVolume = [];
for(var key in data){
var dbId = data[key];
viewer.getProperties(dbId, function(e){
var propertiesObj = e.properties;
propertiesObj.forEach(myF);
function myF(obj){
if(obj.displayName === "Volume"){
var volume = obj.displayValue;
arrayVolume.push(volume);
}
}
});
}
alert(arrayVolume);
}
If that viewer.getProperties is an async operation, like an http call, you should use promises.
For example:
async function kl(data) {
var arrayVolume = [];
for (var key in data) {
var dbId = data[key];
await new Promise((resolve, reject) => {
viewer.getProperties(dbId, (e) => {
var propertiesObj = e.properties;
propertiesObj.forEach(myF);
function myF(obj) {
if (obj.displayName === "Volume") {
var volume = obj.displayValue;
arrayVolume.push(volume);
}
}
return resolve();
});
});
}
alert(arrayVolume);
}

how to make async html parser in nodejs with promises?

having fun with promises in JS and trying to craft simple xpath website parser, but I am struggling with logic on finishing overall parsing process, my code is:
var request = require('request');
var xpath = require('xpath');
var dom = require('xmldom').DOMParser;
var olxMain = 'https://www.some.site/';
var xpathRoot = '//a[contains(#href, "https://www.some.site/mask/")]';
var linksXpath = '//a';
var allGlobalLinks = [];
var getLink = function (node) {
for (key in node['attributes']) {
if (node['attributes'][key]['name'] === 'href') {
return node['attributes'][key]['value'];
}
}
}
var getData = function (url, xpathPattern) {
return new Promise(function (resolve, reject) {
console.log("Opening " + url);
var processResponse = function (error, response, body) {
var doc = new dom().parseFromString(body);
var childNodes = xpath.select(xpathPattern, doc);
var links = childNodes.map(function (n) {
return getLink(n);
});
resolve(links);
};
request({url: url}, processResponse);
}
);
}
var arrayUnique = function (x, i, a) {
return a.indexOf(x) == i;
};
var main = function () {
getData(olxMain, xpathRoot).then(function (links) {
links = links.filter(arrayUnique);
var maxThreads = 10, n = 0;
var chunks = [];
for (k in links) {
var url = links[k];
n++;
if (n <= maxThreads)
chunks.push(url);
else {
n = 0;
// console.log(chunks);
Promise.all(chunks.map(function (url) {
return getData(url, linksXpath);
})).then(function (links) {
// add these links to global scope list here
});
console.log("Finished mappings iteration");
});
chunks = [];
}
}
;
});
}
main();
So what I want is basically some kind of threadPool with promises, how to I manage these 10 promises, when they all are finished, I should spawn another 10 more, until list is finished and all Promises have finished ?

How to make async request in cycle?

var userName = 'realgrumpycat';
var moreAvailable = true;
var lastId = '';
while (moreAvailable)
{
getPhotosDataFromRequest(userName, lastId).then(function (data)
{
moreAvailable = data.more_available;
lastId = data[data.length - 1].id;
console.log(data);
});
}
getPhotosDataFromRequest() returns new Promise() and JSON with data. I'd like to execute this method several times at cyscle. But as I see at debugger, while loop executes so fast, that doesn't step into promise then block
Try using function recursion:
var userName = 'realgrumpycat';
var lastId = '';
var getPhotos = function()
{
getPhotosDataFromRequest(userName, lastId).then(function (data)
{
lastId = data[data.length - 1].id;
console.log(data);
if (data.more_available)
{
getPhotos();
}
});
};
getPhotos();
just as iterative alternative (as concept), but not really a solution in real life, because of performance and limits:
//i try to use here es5 only
var userName = 'realgrumpycat';
var moreAvailable = true;//<-- can be removed
var lastId = ''; //<-- can be removed
var maxRequests = 1000; //e.g. max 1000 requests
//create empty promise to resolve later
var resolveStart = null;
var request = new Promise(function(resolve){
resolveStart = resolve;
});
//append 1000 potential requests
for(var i = 0; i < maxRequests; i++) {
request = request.then(createRequestPromise);
}
//here you probably should differ the "done" rejection and other errors
request.catch(function(){});
//now resolve the first promise, with empty string, to start the request chain
resolveStart('');
function createRequestPromise(lastId) {
return getPhotosDataFromRequest(userName, lastId).then(function (data)
{
lastId = data[data.length - 1].id;
console.log(data);
//stop the chain by rejection
if (!data.more_available) return Promise.reject('done');
return lastId;
});
}

How to return value from helper function back to server.js NodeJS

For my project I have a server.js that calls a helper function place-search.js as shown below.
var express = require('express');
var server = express.Router();
var placeSearch = require("./helpers/place-search");
var obj = "hello";
server.use(function(req, res, next) {
console.log(req.method, req.url);
next();
});
server.post('/', function(req, res) {
/* get the object passed by the client's post request */
obj = req.body;
//console.log("Obj: " + obj);
/* send the confirmation back to the client */
res.status(200).send("body");
placeSearch.placeSearch(obj);
});
module.exports.server = server;
Here is my place-search.js :
var config = require("./config.js");
var Promise = require('bluebird');
var DistanceMatrix = require("./distance-matrix.js");
var GooglePlaces = Promise.promisifyAll(require("googleplaces"));
var googlePlaces = new GooglePlaces(config.apiKey, config.outputFormat);
var extract = require('./extract.js');
var combination = require('./combination_ver2.js');
var permutation = require('./permutation.js');
function placeSearch(obj) {
console.log("Inside place search!");
/**
* Place search - https://developers.google.com/places/documentation/#PlaceSearchRequests
*/
var arr = [];
var count = 0;
var rad = obj["radius"];
console.log("radius: " + rad);
var loc = obj["location"];
console.log("Location: " + loc);
var mode = obj["mode"];
var params = obj["params"];
/* client's keywords */
var arr;
var ar = [];
for (var i = 0; i < params; i++) {
arr[i] = obj[i];
console.log(arr[i]);
var param = {
location: loc,
radius: rad,
mode: mode,
keyword: arr[i]
};
ar.push(param);
}
console.log("before promises");
var promises = ar.map(function(name) {
return googlePlaces.placeSearch(name, function(response) {
arr.push(response);
console.log(response);
console.log(count++);
//If all responses have been returned
//Find combos and pass to distance-matrix
if (count == ar.length) {
var Matrix = new Array();
var result = new Array();
//to extract only lat and lng from arr.results
//Matrix = extract.extract(arr);
result = combination.combination(arr);
// NOW RESULT IS THE ARRAY OF ALL COMBINATION
// NOW RESULT IS THE ARRAY OF COMBINATIONS OF latlng pairs AND PASS IT TO FRONTEND
/*result.forEach(function(combo, index) {
console.log("combo" + combo)
DistanceMatrix.distanceMatrix(mode, combo, result.length);
});*/
// IF YOU WANT TO SEE PERMUTATION
//permutation.permutation(result);
console.log("combination results: " + result);
}
})
});
}
module.exports.placeSearch = placeSearch;
My problem is I do not know how to pass the result variable back to the server.js so that I can use that result as an input for another helper function. I can not for the life of me figure out how to do this. Any help at all would be greatly appreciated.
Well, I don't see your placeSearch function returning anything at all right now, nor doing any kind of callback. Your placeSearch function should expose a callback parameter, which then gets called once you have the answer you want to send back.
Your server file will then take action on that callback. Abbreviating your code, it'd look something like this:
server.post('/', function(req, res) {
/* get the object passed by the client's post request */
obj = req.body;
//console.log("Obj: " + obj);
placeSearch.placeSearch(obj, function(error, data){
/* send the data back to the client */
res.status(200).send(data);
});
});
To support that, your placeSearch function will have to call its callback when appropriate:
function placeSearch(obj, callback){
/* all the stuff you do to assemble your data */
// if (there_is_some_error):
if(err) return cb(err);
// when you have all your data available, no error has occurred
return cb(null, data);
}
Something else you might notice is that your ar.map won't work as you seem to expect. ar.map is a synchronous function, you're calling async code inside... not gonna work the way you think. It's a bit long for this post, but you should look at the async library from npm to manage an array of asynchronous requests to collect one combined result.
use callback your code looks like this:
function placeSearch(obj,callback) {
console.log("Inside place search!");
/**
* Place search - https://developers.google.com/places/documentation/#PlaceSearchRequests
*/
var arr = [];
var count = 0;
var rad = obj["radius"];
console.log("radius: " + rad);
var loc = obj["location"];
console.log("Location: " + loc);
var mode = obj["mode"];
var params = obj["params"];
/* client's keywords */
var arr;
var ar = [];
for (var i = 0; i < params; i++) {
arr[i] = obj[i];
console.log(arr[i]);
var param = {
location: loc,
radius: rad,
mode: mode,
keyword: arr[i]
};
ar.push(param);
}
console.log("before promises");
var promises = ar.map(function(name) {
return googlePlaces.placeSearch(name, function(response) {
arr.push(response);
console.log(response);
console.log(count++);
//If all responses have been returned
//Find combos and pass to distance-matrix
if (count == ar.length) {
var Matrix = new Array();
var result = new Array();
//to extract only lat and lng from arr.results
//Matrix = extract.extract(arr);
result = combination.combination(arr);
// NOW RESULT IS THE ARRAY OF ALL COMBINATION
// NOW RESULT IS THE ARRAY OF COMBINATIONS OF latlng pairs AND PASS IT TO FRONTEND
/*result.forEach(function(combo, index) {
console.log("combo" + combo)
DistanceMatrix.distanceMatrix(mode, combo, result.length);
});*/
// IF YOU WANT TO SEE PERMUTATION
//permutation.permutation(result);
console.log("combination results: " + result);
callback(null,result);
}
})
});
}
in server.js:
server.post('/', function(req, res) {
/* get the object passed by the client's post request */
obj = req.body;
//console.log("Obj: " + obj);
/* send the confirmation back to the client */
res.status(200).send("body");
placeSearch.placeSearch(obj,function(err,result){
if(!err){
console.log(result);
}
})
});
It seems like you're having trouble with the async operation. You'll want to return the promise from your place-search module. You'll also need to convert the callbacks from placeSearch into a promise.
EDIT: updated since googlePlaces.placeSearch doesn't return a promise
inside placeSearch
function placeSearch(obj) {
//...
var promises = ar.map(function(name) {
var placeDefer = Q.defer();
return googlePlaces.placeSearch(name, function(response) {
placeDefer.resolve(response); // or placeDefer.reject if a failure occurs
});
return placeDefer.promise;
});
return promises;
}
and in your route:
// I'm going to just assume Q promise library here
var Q = require("q");
server.post('/', function(req, res) {
/* get the object passed by the client's post request */
obj = req.body;
//console.log("Obj: " + obj);
/* send the confirmation back to the client */
res.status(200).send("body");
Q.all(placeSearch.placeSearch(obj))
.spread(function() {
var places = Array.prototype.slice.call(arguments);
// possibly call res.status(200).send("body"); here?
// only if you're trying to use the places in your response
});
});

How to return array from JavaScript function that retrieves data from text file?

I am building a Windows 8 Store app with HTML/CSS/JavaScript. I am reading in data from a text file through a function, and then putting that data into an array. I am trying to return the array through the function, but it is not working. Any help would be greatly appreciated. I've attached my code snippet.
// Load user data
var DefineUserData = function LoadUserData() {
return Windows.Storage.ApplicationData.current.localFolder.getFileAsync(loadfile).done(function (UserFile) {
return Windows.Storage.FileIO.readTextAsync(UserFile).done(function (fileResult) {
var userdata = new Object();
var dataobject = {};
var innercount;
var outercount;
var fileResultByLines = fileResult.split("\n");
for (outercount = 0; outercount <= (fileResultByLines.length - 2) ; outercount++) {
var tempArray = fileResultByLines[outercount].split(",");
dataobject.metrictitle = tempArray[0];
dataobject.numinputs = tempArray[1];
dataobject.inputs = new Array();
for (innercount = 0; innercount <= parseInt(dataobject.numinputs) ; innercount++) {
dataobject.inputs[innercount] = tempArray[innercount + 2];
}
userdata[outercount] = dataobject;
}
return userdata;
});
},
function (errorResult) {
document.getElementById("resbutton1").innerText = errorResult;
})
}
Your DefineUserData function is returning a Promise, not a value. Additionally done functions don't return anything. Instead you'll need to use then functions instead of done functions in DefineUserData and then handle add a done function (or then) to the code that calls this function.
Also, You can make your promises easier to read, and easier to work with by chaining then functions instead of nesting them.
Currently on Win7 at the office so I can't test this, but try something similar to this pseudo-code. Note then functions instead of done. The last then returns your data. Sample snippet afterwards to illustrate calling this and handling the result.
// modified version of yours
var DefineUserData = function LoadUserData() {
return Windows.Storage.ApplicationData.current.localFolder
.getFileAsync(loadfile)
.then(function (UserFile) {
return Windows.Storage.FileIO.readTextAsync(UserFile);
}).then(function (fileResult) {
var userdata = new Object();
var dataobject = {};
var innercount;
var outercount;
var fileResultByLines = fileResult.split("\n");
for (outercount = 0; outercount <= (fileResultByLines.length - 2) ; outercount++) {
var tempArray = fileResultByLines[outercount].split(",");
dataobject.metrictitle = tempArray[0];
dataobject.numinputs = tempArray[1];
dataobject.inputs = new Array();
for (innercount = 0; innercount <= parseInt(dataobject.numinputs) ; innercount++) {
dataobject.inputs[innercount] = tempArray[innercount + 2];
}
userdata[outercount] = dataobject;
}
return userdata;
},
function (errorResult) {
document.getElementById("resbutton1").innerText = errorResult;
});
}
// some other code...
DefineUserData.done(function (userdata) {
// do something
});

Categories

Resources