Asynchronous function is not printing any output except for null - javascript

I'm new to asynchronous code and I'm not quite sure why the code is not producing the expected output.
When the 'console.log(data.imdb_id)' is uncommented is prints the required ids one by one, but otherwise just prints a "null" from the 'console.log(err)' line.
How do I fill my promiseArray with the required values and return this array for later use?
var movie_ids = [
474350, 522938, 540901,
384018, 419704, 420818,
521029, 301528, 484641,
515195, 466272, 441282,
423204, 533642, 530385,
568012, 535544, 456740,
523077, 531309
]
async function insert_ids(movie_ids) {
var promiseArray = [];
for (var i = 1; i <= movie_ids.length; i++) {
promiseArray.push(new Promise((resolve, reject) => {
var url1 = "FIRST PART";
var url2 = "SECOND PART";
request(url1 + movie_ids[i] + url2, function (err, res, body) {
if (!err & res.statusCode == 200) {
var data = JSON.parse(body);
resolve(data.imdb_id);
// console.log(data.imdb_id); > This prints the correct ids
} else {
console.log(err); > Prints "null"
}
});
}));
};
await Promise.all(promiseArray).then(function(result) {
console.log(result);
});
}
insert_ids(movie_ids);

Related

Javascript print all the status at a time using request node module

I'm new to javascript and promises, I had a requirement where I need to get the http status of my URL's(i have 10 URL's) all at a time (Not sequentialy).
So I wrote below code.
var request = require('request');
var fun = function(i) {
request('http://myapp' + i + '.com', function(error, response, body) {
console.log(response && response.statusCode, i);
});
};
for (i = 0; i < 10; i++) {
fun(i);
}
but I'm getting
status1 then status2 then status3 and so on..... my requirement is to print all the status at one time.
then tried below code
var request = require('request');
var fun = function(myapp) {
return new Promise(function(resolve, reject) {
request('http://' + myapp + '.com', function(error, response, body) {
resolve(response && response.statusCode);
});
});
};
for (i = 0; i < 10; i++) {
fun('myapp' + i).then(function(val1) {
console.log(val1);
});
}
but still, I'm getting status1 then status2 then status3 and so on.....
Any help is appreciated.
You could collect all the promises in an array, then use Promise.all on that to get an array of results:
const promises = [];
for (i = 0; i < 10; i++) {
promises.push( fun('myapp' + i));
Promise.all(promises)
.then(console.log, console.error);
Your code is correct. It executes asynchronously in parallel.
However you are confused into seeing output be printed in sequence (or what looks like sequence) but this is normal, no matter if parallel or synhronous, output (as it is coded will be printed one after the other, maybe not in same order).
if you want to output all at once when finished, do sth like the following:
var request = require('request');
var finished = new Array(10);
var numFinished = 0;
var fun = function(i) {
request('http://myapp' + i + '.com', function(error, response, body) {
finished[i] = response && response.statusCode ? response.statusCode : 'No response';
numFinished++;
});
};
for (i = 0; i < 10; i++) {
fun(i);
}
var timer = setTinterval(function(){
if ( 10 <= numFinished )
{
clearInterval(timer);
console.log(finished.join(',')); // print all at once
}
}, 500);
Or if you use promises you can do:
var request = require('request');
var fun = function(myapp) {
return new Promise(function(resolve, reject) {
request('http://' + myapp + '.com', function(error, response, body) {
resolve(response && response.statusCode ? response.statusCode : 'No response');
});
});
};
var promises = new Array(10);
for (i = 0; i < 10; i++) {
promises[i] = fun('myapp' + i);
Promise.all(promises).then(function(results){
console.log(results.join(',')); // print all at once
});

Why is my code not waiting for the completion of the function?

I am trying to read some data from a file and store it in a database.
This is part of a larger transaction and I need the returned ids for further steps.
async parseHeaders(mysqlCon, ghID, csv) {
var self = this;
var hIDs = [];
var skip = true;
var idx = 0;
console.log("Parsing headers");
return new Promise(async function(resolve, reject) {
try {
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream(csv)
});
await lineReader.on('close', async function () {
console.log("done: ", JSON.stringify(hIDs));
resolve(hIDs);
});
await lineReader.on('line', async function (line) {
line = line.replace(/\"/g, '');
if (line.startsWith("Variable")) { //Variable,Statistics,Category,Control
console.log("found variables");
skip = false; //Ignore all data and skip to the parameter description.
return; //Skip also the header line.
}
if (!skip) {
var data = line.split(",");
if (data.length < 2) { //Variable section done return results.
console.log("Found sub?",line);
return lineReader.close();
}
var v = data[0];
var bidx = data[0].indexOf(" [");
if (bidx > 0)
v = data[0].substring(0, bidx); //[] are disturbing mysql (E.g.; Air temperature [�C])
var c = data[2];
hIDs[idx++] = await self.getParamID(mysqlCon, ghID, v, c, data);//, function(hID,sidx) { //add data in case the parameter is not in DB, yet.
}
});
} catch(e) {
console.log(JSON.stringify(e));
reject("some error occured: " + e);
}
});
}
async getParamID(mysqlCon,ghID,variable,category,data) {
return new Promise(function(resolve, reject) {
var sql = "SELECT ID FROM Parameter WHERE GreenHouseID="+ghID+" AND Variable = '" + variable + "' AND Category='" + category + "'";
mysqlCon.query(sql, function (err, result, fields) {
if(result.length === 0 || err) { //apparently not in DB, yet ... add it (Acronym and Machine need to be set manually).
sql = "INSERT INTO Parameter (GreenHouseID,Variable,Category,Control) VALUES ("+ghID+",'"+variable+"','"+category+"','"+data[3]+"')";
mysqlCon.query(sql, function (err, result) {
if(err) {
console.log(result,err,this.sql);
reject(err);
} else {
console.log("Inserting ",variable," into DB: ",JSON.stringify(result));
resolve(result.insertId); //added, return generated ID.
}
});
} else {
resolve(result[0].ID); //found in DB .. return ID.
}
});
});
}
The functions above are in the base class and called by the following code:
let headerIDs = await self.parseHeaders(mysqlCon, ghID, filePath);
console.log("headers:",JSON.stringify(headerIDs));
The sequence of events is that everything in parseHeaders completes except for the call to self.getParamID and control returns to the calling function which prints an empty array for headerIDs.
The console.log statements in self.getParamID are then printed afterward.
What am I missing?
Thank you
As you want to execute an asynchronous action for every line we could define a handler to do right that:
const once = (target, evt) => new Promise(res => target.on(evt, res));
function mapLines(reader, action) {
const results = [];
let index = 0;
reader.on("line", line => results.push(action(line, index++)));
return once(reader, "close").then(() => Promise.all(results));
}
So now you can solve that easily:
let skip = false;
const hIDs = [];
await mapLines(lineReader, async function (line, idx) {
line = line.replace(/\"/g, '');
if (line.startsWith("Variable")) { //Variable,Statistics,Category,Control
console.log("found variables");
skip = false; //Ignore all data and skip to the parameter description.
return; //Skip also the header line.
}
if (!skip) {
var data = line.split(",");
if (data.length < 2) { //Variable section done return results.
console.log("Found sub?",line);
return lineReader.close();
}
var v = data[0];
var bidx = data[0].indexOf(" [");
if (bidx > 0)
v = data[0].substring(0, bidx); //[] are disturbing mysql (E.g.; Air temperature [�C])
var c = data[2];
hIDs[idx] = await self.getParamID(mysqlCon, ghID, v, c, data);
}
});

Order of Promise Resolution Not As Expected in Promise-Containing For-Loop

I need to perform a rather complicated chain of promise resolutions to get and save data that is located in PDFs that are uploaded by a user. Everything works fine for single PDFs, but it breaks as soon as I try to upload multiple PDFs because the order in which the resolution proceeds isn't as I expect.
I call the function saveDoc on each file in an array:
saveDoc: function(){
var files = this.$refs.upload.uploadFiles
var self=this;
var promises = []
for (var i=0; i<files.length; i++){
(function(){
var file = files[i]
var name = file['name']
if (!(/\.pdf/i.test(name))){
name+='.pdf'
}
var type = mime.lookup(name)
var file = file['raw'];
var beforeUrl = self.selectedCategories.join('&&&')
console.log('going to save: ' + name) // Because of the IIFE, I'm not expecting this to log only after all steps 1 - 20 have been completed for each file
Store.getFileData(file).then(function(data){
console.log(2)
return Store.saveDoc(name, type, data, beforeUrl).then(url => {
console.log(8)
return Text.getText(url).then(text => {
console.log(12)
return Text.getMetadata(text, url).then(metadata => {
console.log(20)
if (metadata.length){
return Store.saveMetadata(beforeUrl, metadata, name)
}
return Store.createCategory(name, self.selectedCategories, '')
})
})
})
})
})()
}
},
I'm sure the promises could use some work, but what seems to be the problem is that the line console.log('going to save: ' + name) is called twice before the entire sequence 1-20 is carried out for one file (see error message of number sequence at bottom of this post). I tried to prevent this using an IIFE, but I guess I didn't do this right.
store.js
getData: function(url){
return new Promise(function(accept, reject){
console.log(4)
documentation.get(url, function(err, body) {
console.log(5)
if (!err){
console.log(body);
accept(body)
}
});
})
},
getFileData: function(file){
var reader = new FileReader();
return new Promise(function(accept, reject){
console.log(1)
reader.onload = (e) => {
// var data = e.target.result.replace(/^data:[A-Za-z]+\/[A-Za-z]+;base64,/, '')
// console.log('base 64: ' + data)
var res = new Uint8Array(e.target.result)
accept(res)
};
reader.readAsArrayBuffer(file);
})
},
saveDoc: function(name, type, filedata, url){
console.log(3)
var self=this
return new Promise(function(accept, reject){
return self.getData(url).then(data => {
console.log(6)
var rev = data['_rev']
return documentation.attachment.insert(url, name, filedata, type,
{ rev: rev }, function(err, body) {
if (!err){
console.log(7)
var fullUrl = 'http://dev04/documentation/'+url+'/'+name
accept(fullUrl)
}
else {
console.log(err)
}
})
}).catch(err => {
console.log(err)
})
})
},
saveMetadata: function(url, metadata, name){
var fileName = path.basename(name)
var self=this
return new Promise(function(accept, reject){
self.getData(url).then(data => {
var meta
var rev = data['_rev']
if(!data['metadata']){
data['metadata'] = {}
}
data['metadata'][fileName] = metadata
var datastring = JSON.stringify(data)
documentation.insert(data, url, function(err, body, header) {
if (err) {
console.log(err.message);
return;
}
});
}).catch(err => {
console.log(err)
})
})
},
text.js
export default {
getText: function(url){
console.log(9)
var result = []
return new Promise(function(accept, reject){
console.log(10)
return pdfjs.getDocument(url).then(pdf => {
console.log(11)
var pdf = pdfjs.getDocument(url);
return pdf.then(function(pdf) { // get all pages text
var maxPages = pdf.pdfInfo.numPages;
var countPromises = []; // collecting all page promises
for (var j = 1; j <= maxPages; j++) {
var page = pdf.getPage(j);
var txt = "";
countPromises.push(page.then(function(page) { // add page promise
var textContent = page.getTextContent();
// console.log('the content is ' + textContent)
return textContent.then(function(text){ // return content promise
var val = text.items.map(function (s) { return s.str; }).join('&&&')+'&&&'; // value page text
result.push(val)
// console.log(val + ' should be one page of text')
return val
});
}));
}
// Wait for all pages and join text
return Promise.all(countPromises).then(function (texts) {
accept(texts.join(''))
});
});
});
})
},
getMetadata: function(text, url){
console.log(13)
var result = []
var self = this
return new Promise(function(accept, reject){
self.getpageno(url).then(function(pagecount){
console.log(19)
try {
var dataMatch = rx.exec(text)
var produktDaten = dataMatch[1].split("&&&").filter(Boolean);
console.log(produktDaten)
var dokuArr = dataMatch[2].split("&&&").filter(Boolean);
for (var i=0; i<produktDaten.length; i+=4){
var entry = {}
entry.pagecount = pagecount
entry.kks = {}
entry.kks.pages = {}
var kksNummer = produktDaten[i];
entry.kks.nummer = kksNummer;
for(var j=0; j<dokuArr.length; j+=3){
var nummer = dokuArr[j];
var beschreibung = dokuArr[j+1];
var seite = dokuArr[j+2];
// make sure seite is a digit
if (!(/^\d+$/.test(seite))){
console.log(seite + ' was not a valid page number')
throw err
}
if (/(A|a)lle?/i.test(nummer)){
entry.kks.pages[beschreibung] = seite;
// self.tableEntry.kks.url = url;
// self.tableEntry.fileName = name;
///// kksNummern.forEach(function(kks){
// self.tableEntry.kks;
// })
}
else if (nummer === kksNummer) {
entry.kks.pages[beschreibung] = seite;
// entry.kks.url = url;
// entry.fileName = name
}
}
entry.hersteller = produktDaten[i+1]
entry.typ = produktDaten[i+2]
entry.artikelNummer = produktDaten[i+3]
result.push(entry)
}
}
catch(e){
return accept(result)
}
return accept(result)
/* if (result.length>0){
console.log('accepting the result')
}
reject()*/
}).catch(err => {
console.log(err)
})
})
},
getpageno: function(url){
console.log(14)
var self=this
var pdf = pdfjs.getDocument(url);
return pdf.then(function(pdf){
console.log(15)
var maxPages = pdf.pdfInfo.numPages;
var countPromises = []; // collecting all page promises
for (var j = 1; j <= maxPages; j++) {
try {
var page = pdf.getPage(j);
var txt = "";
countPromises.push(page.then(function(page) { // add page promise
var textContent = page.getTextContent();
return textContent.then(function(text){ // return content promise
console.log(16)
return text.items.map(function (s) { return s.str; }).join('&&&'); // value page text
});
}));
}
catch(e){
console.log(e)
}
}
// Wait for all pages and join text
return Promise.all(countPromises).then(function (texts) {
// since doumentation pages do not add the final '&&&', must add one manually (only after rx has been found)
console.log(17)
var fulltext = texts.reduce(function(full, text){
if (rx.test(full)){
var next = '&&&'+text
return full+=next
}
return full+=text
}, '')
return [fulltext, texts]
});
}).then(function(textarr){
console.log(18)
var fulltext = textarr[0]
self.fulltext = fulltext;
var texts = textarr[1]
try {
var partialmatch = rx.exec(fulltext)[0]
var count = texts.reduce(function(pageno, text){
var tomatch = text.replace(/.*Typ&&&/, '')
if (tomatch.length>0 && partialmatch.indexOf(tomatch) > -1){
pageno++
}
return pageno;
}, 0)
}
catch(e){
console.log(e)
}
return count;
}).catch(err => {console.log(err)})
}
}
I use the console to log the order I am expecting for the functions. I am expecting the numbers 1 - 20 in order, but I get the following.
going to save: 03_.pdf selector.js:211:6
1 store.js:227:4
going to save: 2017.07.05_0016 E161206.pdf selector.js:211:6
1 store.js:227:4
2 selector.js:213:7
3 store.js:239:3
4 store.js:213:4
2 selector.js:213:7
3 store.js:239:3
4 store.js:213:4
5 store.js:215:5
Object { _id: "Test", _rev: "36-85a08c0852ccab78c0b4c10369e83fb2", rank: 7, icon: "wrench", metadata: Object, _attachments: Object } store.js:217:6
6 store.js:243:5
5 store.js:215:5
Object { _id: "Test", _rev: "36-85a08c0852ccab78c0b4c10369e83fb2", rank: 7, icon: "wrench", metadata: Object, _attachments: Object } store.js:217:6
6 store.js:243:5
7 store.js:247:7
8 selector.js:215:8
9 text.js:12:3
10
11 text.js:17:5
12 selector.js:217:9
13 text.js:50:3
14 text.js:112:3
15 text.js:116:4
16 text.js:129:8
17 text.js:142:5
18 text.js:153:4
19 text.js:57:5
20
Can anyone offer any advice on how to get this order correct? Thank you.

why isn't this promise resolving?

I have a promise that is meant to collect metadata on a file and then resolve it with the metadata that was collected. Here is how I am trying to get its result:
getMetadata: function(text, url){
return this.getpageno(url).then(function(pagecount){
return new Promise(function(accept, reject){
var result = []
var dataMatch = rx.exec(text)
var produktDaten = dataMatch[1].split("&&&").filter(Boolean);
var dokuArr = dataMatch[2].split("&&&").filter(Boolean);
console.log('the produktdaten are ' + produktDaten)
for (var i=0; i<produktDaten.length; i+=4){
var entry = {}
for(var j=0; j<dokuArr.length; j+=3){
var seite = dokuArr[j+2];
// make sure seite is a digit
if (!(/^\d+$/.test(seite))){
console.log(seite + ' was not a valid page number')
throw err
}
if (/(A|a)lle?/i.test(nummer)){
entry.kks.pages[beschreibung] = seite;
// })
}
else if (nummer === kksNummer) {
entry.kks.pages[beschreibung] = seite;
}
}
entry.hersteller = produktDaten[i+1]
entry.typ = produktDaten[i+2]
entry.artikelNummer = produktDaten[i+3]
result.push(entry)
}
if (result.length>0){
return accept(result)
}
return reject()
})
})
},
getpageno: function(url){
var self=this
var pdf = pdfjs.getDocument(url);
return pdf.then(function(pdf){
var maxPages = pdf.pdfInfo.numPages;
var countPromises = []; // collecting all page promises
for (var j = 1; j <= maxPages; j++) {
try {
var page = pdf.getPage(j);
var txt = "";
countPromises.push(page.then(function(page) { // add page promise
var textContent = page.getTextContent();
return textContent.then(function(text){ // return content promise
return text.items.map(function (s) { return s.str; }).join('&&&'); // value page text
});
}));
}
catch(e){
console.log(e)
}
}
// Wait for all pages and join text
return Promise.all(countPromises).then(function (texts) {
// since doumentation pages do not add the final '&&&', must add one manually (only after rx has been found)
var fulltext = texts.reduce(function(full, text){
if (rx.test(full)){
var next = '&&&'+text
return full+=next
}
return full+=text
}, '')
return [fulltext, texts]
});
}).then(function(textarr){
var fulltext = textarr[0]
self.fulltext = fulltext;
var texts = textarr[1]
try {
var partialmatch = rx.exec(fulltext)[0]
var count = texts.reduce(function(pageno, text){
var tomatch = text.replace(/.*Typ&&&/, '')
if (tomatch.length>0 && partialmatch.indexOf(tomatch) > -1){
pageno++
}
return pageno;
}, 0)
}
catch(e){
console.log(e)
}
return count;
})
}
Edited the entry to show that I'm now returning the value of the gepageno function.
The data that I am expecting is logged but not available as a result of accept(). Can anyone tell what could be going wrong?
I have tried to simulate and give a solution of your promise. I have posted pseudo code.
Promise flow
var testFunction = ((result) => {
return new Promise(function (resolve, reject) {
var err = null;
if (!!err) {
reject(err);
} else {
console.log("2. testFunction resolved");
resolve("Final response");
}
});
});
var getpageno = ((url) => {
return new Promise((resolve, reject) => {
var err = null;
if (!!err) {
reject(err);
} else {
console.log("1. getpageno resolved");
resolve(45);
}
});
});
var getMetadata = ((text, url) => {
console.log("0. getmetadata resolved");
var self = this;
getpageno(url)
.then((pageCount) => {
console.log("> pageCount :", pageCount);
return testFunction(pageCount);
})
.then((data) => {
console.log(">", data);
});
});
getMetadata("hell", "https://www.google.com");
output
0. getmetadata resolved
1. getpageno resolved
> pageCount : 452. testFunction resolved
> Final response
you need to return the promise on the third line
return self.getpageno(url).then
to access its eventual fulfillment value.

Request in NodeJS async waterfall return undefined

I'm pretty new to async on node js. I use the waterfall method while parsing a xml file like this:
$('situation').each( function(){
var situation = [];
$(this).find('situationRecord').each( function(i){
var record = this;
async.waterfall([
function (callback){
var filter = {
startLocationCode: $(record).find('alertCMethod2SecondaryPointLocation').find('specificLocation').text(),
endLocationCode: $(record).find('alertCMethod2PrimaryPointLocation').find('specificLocation').text(),
overallStartTime: $(record).find('overallStartTime').text(),
overallEndTime: $(record).find('overallEndTime').text()
}
callback(null, filter, record);
},
function (filter, record, callback){
var timestamp = new Date().toDateInputValue();
var startDbResponse = 0;
var endDbResponse = 0;
if((filter.startLocationCode != '') && new Date(timestamp) >= new Date(filter.overallStartTime) && new Date(timestamp) <= new Date(filter.overallEndTime) ){
startDbResponse = locationCodeToGeodataRequst.geodataByLocationcode(filter.startLocationCode);
endDbResponse = locationCodeToGeodataRequst.geodataByLocationcode(filter.endLocationCode);
}
console.log("startDbResponse: ", startDbResponse);
console.log("endDbResponse: ", endDbResponse);
callback(null, filter, record, startDbResponse, endDbResponse);
},
function (filter, record, startDbResponse, endDbResponse, callback){
console.log("startDbResponse: ", startDbResponse);
console.log("endDbResponse: ", endDbResponse);
var situationRecord = createSituationRecord($, record, filter.startLocationCode, filter.endLocationCode, startDbResponse, endDbResponse);
console.log(situationRecord);
},
function (situationRecord, callback){
situation[i] = { situationRecord };
}
],
function(err, results){
console.error("There was an error by filtering the xml file");
console.error(err);
});
})
if(situation.length > 0){ //if situation is not empty
locations.push(situation);
}
})
console.log(locations);
}
In this part of the waterfall I make a request to my database with locationCodeToGeodataRequst.geodataByLocationcode(filter.startLocationCode); but startDbResponse and endDbResponse is undefined :
....
function (filter, record, callback){
var timestamp = new Date().toDateInputValue();
var startDbResponse = 0;
var endDbResponse = 0;
if((filter.startLocationCode != '') && new Date(timestamp) >= new Date(filter.overallStartTime) && new Date(timestamp) <= new Date(filter.overallEndTime) ){
startDbResponse = locationCodeToGeodataRequst.geodataByLocationcode(filter.startLocationCode);
endDbResponse = locationCodeToGeodataRequst.geodataByLocationcode(filter.endLocationCode);
}
console.log("startDbResponse: ", startDbResponse);
console.log("endDbResponse: ", endDbResponse);
callback(null, filter, record, startDbResponse, endDbResponse);
},
....
The request by it self works because a console.log in the request module show the correct data. So I don't understand why its undefined.
This is the request module:
exports.geodataByLocationcode = function geodataByLocationcode(locationcode){
let sql = "SELECT * FROM tmc WHERE LOCATION_CODE = " + locationcode;
let query = db.query(sql, (err, result) =>{
if(err == null){
//console.log(result);
return result;
}else{
console.log("Error by getting item from db: " + err);
throw err;
}
});
}
This is a snipped of the console.log:
....
startDbResponse: undefined
endDbResponse: undefined
startDbResponse: undefined
endDbResponse: undefined
startDbResponse: 0
endDbResponse: 0
startDbResponse: 0
endDbResponse: 0
[]
//here comes the output of the requests as json objects
....
move the console log to the last function of async. As Manjeet pointed out async takes time and console prints early.
function (situationRecord, callback){
situation[i] = { situationRecord };
if(situation.length > 0){ //if situation is not empty
locations.push(situation);
}
})
console.log(locations);
}
}

Categories

Resources