I have the following loop in node.js
for (var i in details) {
if (!details[i].AmntRcvd > 0) {
res.sendStatus(400);
return;
}
totalReceived += details[i].AmntRcvd;
UpdateDetail(details[i].PONbr, details[i].LineID).then((results) => {
console.log(results);
details[i].QtyOrd = results.QtyOrd;
details[i].QtyRcvd = results.QtyRcvd;
details[i].QtyPnding = results.QtyPnding;
details[i].UnitCost = results.UnitCost;
}).catch((error) => {
console.log(error);
});
}
The UpdateDetail function returns a promise. How do I wait for the promise to resolve/reject before moving on to the next iteration of the loop.
You can use the await keyword to solve this. more info here
async function main() {
for (var i in details) {
if (!details[i].AmntRcvd > 0) {
res.sendStatus(400);
return;
}
try {
totalReceived += details[i].AmntRcvd;
let results = await UpdateDetail(details[i].PONbr, details[i].LineID);
console.log(results);
details[i].QtyOrd = results.QtyOrd;
details[i].QtyRcvd = results.QtyRcvd;
details[i].QtyPnding = results.QtyPnding;
details[i].UnitCost = results.UnitCost;
}
catch(e) {
console.log(error);
}
}
}
You can use await:
for (var i in details) {
if (!details[i].AmntRcvd > 0) {
res.sendStatus(400);
return;
}
totalReceived += details[i].AmntRcvd;
await UpdateDetail(details[i].PONbr, details[i].LineID).then((results) => {
console.log(results);
details[i].QtyOrd = results.QtyOrd;
details[i].QtyRcvd = results.QtyRcvd;
details[i].QtyPnding = results.QtyPnding;
details[i].UnitCost = results.UnitCost;
}).catch((error) => {
console.log(error);
});
console.log('done with ' + i)
}
Here's the documentation:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
You can use async library for this.then go for async.eachSeries.
You need to do npm install async first
Here is the example:
var async = require('async');
async.eachSeries(yourarray,function(eachitem,next){
// Do what you want to do with every for loop element
next();
},function (){
//Do anything after complete of for loop
})
Related
I am trying to break from the loop in an async function in node js, but it seems not to work. Once the script it's done, it starts executing again from the beginning. I can't use process.exit(), because then it won't save my logs.
Any idea how can I terminate this function?
Here is the code:
async function program() {
const xlsxFile = require('read-excel-file/node');
let rows = await xlsxFile('./file.xlsx', { sheet: 'sheet' });
const userRolesArray = [rows[0][1], rows[0][2]];
let roles = await getAllRoles();
let users = await getAllUsers();
let count = 0;
roleId = null;
for (userRole in userRolesArray) {
for (i in rows){
let someObject = {
test1: rows[i][0],
test1: rows[i][2],
};
if (someObject.test1 =='undefined') {
fs = require('fs')
await fs.appendFile('log_file.txt', i+")"+JSON.stringify(someObject)+"\n", function (err) {
if (err) throw err;
// console.log('Saved!');
});
} else {
//do something else;
}
}
}
count++;
if (userRole === '1') {
// loop has reached the end...Now exit
break;
}
};
program().then(() => {
return "Finished....!"
});
Hi I have a for loop in my node js application which calls an async function. I want to check a value and decide whether a customer is found or not. But the loop iterates until the last element. Hence my error loop is not working. I want the loop to check the response and then iterate the next loop.
for loop:
for (let i = 0; i < customerlookupresponse.data.length; i++) {
var customer = customerlookupresponse.data[i];
if (customer != undefined) {
console.log("customer.id :: " + customer.id)
var accountlookUpData = {
customerId: customer.id
};
customerAccountLookUpRequest(accountlookUpData).then(data => {
console.log("----" + i + " -- " + data);
if (data && data.status === 1) {
resolve(data);
return;
}else{
reject({
status: 404,
message: "Customer not found"
});
return;
}
});
} else {
reject({
status: 404,
message: "Customer not found"
});
return;
}
}
the async function:
async function customerAccountLookUpRequest(customerLookUpData) {
var accountLookUp = config.app.url;
let data = await axios.get(accountLookUp).then(accountLookUpResult => {
for (i = 0; i < accountLookUpResult.data.length; i++) {
var requestaccount = accountLookUpResult.data[i].accountNumber;
if (requestaccount == customerLookUpData.lookupAccount) {
accountLookUpResult.data[i].customerId = customerLookUpData.customerId;
accountLookUpResult.data[i].status = 1;
return accountLookUpResult.data[i];
}
}
});
return data;
}
I am new to node js and trying to understand the concept of async await. Please help.
An async function waits for a Promise to return. The function that has the loop should be declared as async and the customerAccountLookUpRequest function should return a promise. Then use the await operator to call the function. Simple example:
class some_class {
constructor() {
}
async my_loop() {
let _self = this;
for (let i = 0; i < customerlookupresponse.data.length; i++) {
let data = await _self.customerAccountLookUpRequest(accountlookUpData);
console.log("----" + i + " -- " + data);
}
}
customerAccountLookUpRequest(customerLookUpData) {
return new Promise((resolve, reject) => {
axios.get(accountLookUp).then(accountLookUpResult => {
resolve(accountLookUpResult);
});
});
}
}
My objective is to read data from two files and compare the data. My input files are result3.json and result4.json.The data in these files are coma separated.
result3.json
[
"temp1.txt",
"temp2.txt",
]
node:
function readFromFile(file) {
var fileNames = [];
//setTimeout(function() {
fs.readFile(file,function(err, data){
if (err) {
return console.log(err);
}
var temp = JSON.parse(data.toString().split(","));
// console.log(temp.length);
for (let index = 0; index < temp.length; index++) {
//console.log(temp[index]);
fileNames.push(temp[index]);
//console.log(fileNames[index]);
}
Done(); // to block the async call
});
//},3000);
//console.log(fileNames.length);
return fileNames;
}
var baseListOfFiles = readFromFile('./output/result3.json'); // Assume this is the base file
var currentListOfFiles = readFromFile('./output/result4.json'); // Assume this is the current file
function Done(){
//console.log('Out baseListOfFiles + ' + baseListOfFiles.length);
for (let index = 0; index < baseListOfFiles.length; index++) {
console.log("[baseListOfFiles] " + baseListOfFiles[index]);
}
//console.log('Out currentListOfFiles+ ' + currentListOfFiles.length);
for (let index = 0; index < currentListOfFiles.length; index++) {
console.log("[currentListOfFiles] " + currentListOfFiles[index]);
}
}
Above is my code. It seems to be async call, so it always return 0 fileNames.
Is there any way to control it?
Here's example code using Promises:
const fs = require('fs');
function readFromFile(file) {
return new Promise((resolve, reject) => {
fs.readFile(file, function (err, data) {
if (err) {
console.log(err);
reject(err);
}
else {
resolve(JSON.parse(data));
}
});
});
}
const promises = [
readFromFile('./output/result3.json'),
readFromFile('./output/result4.json')
];
Promise.all(promises).then(result => {
console.log(result);
baseListOfFiles = result[0];
currentListOfFiles = result[1];
// do more stuff
});
First, an array promises is built; each Promise reads the file, then calls resolve with the result.
This array is passed to Promise.all(), which then calls the callback, passing the array of results in the same order.
You're right, readFile is async. What you're looking for is readFileSync: https://nodejs.org/api/fs.html#fs_fs_readfilesync_path_options
With that can can do:
const data = fs.readFileSync(file);
//do something with data
There are a few ways to 'promisify' readFile if you like, the options are discussed here: Using filesystem in node.js with async / await
I am trying to iterate through the JSON files generated by the protractor tests. I pull all the file names into an array and call a method that opens and parses through the each file, post the results to the database and pass back a passed/failed flag.
I have tried all the examples here
Make angular.forEach wait for promise after going to next object and still get the same results.
The method is actually called, but the results are not posted to the db. I have tested the parser.parseResults on an individual file and it successfully posted to the db, so it has to have something to do with the promise not resolving correctly.
Is it not possible to do something like this in the jasmine/protractor framework? Or do I have something wrong in the code?
I have included the code for my latest attempt.
Thank You
Christine
matches.reduce(function (p, val) {
console.log('val', val);
return p.then(function () {
return parser.parseResults(val);
});
}, Promise.resolve()).then(function (finalResult) {
console.log('finalResult = ', finalResult);
}, function (err) {
console.log('error in reduce',err);
});
parser.parseResults code
protractorParser.prototype.parseResults = function (fileName) {
return new Promise((resolve, reject) => {
console.log('In parseresults', fileName);
json.readFile(fileName, function (err, obj) {
try {
if (err != null) {
console.log('error reading file',err);
reject(err);
}
console.log('obj - ',obj);
var results = [];
var Passed = 0;
var Message = '';
var Stack = '';
for (var suite in obj) {
var specs = obj[suite].specs;
console.log('spec - ', specs);
if (specs.length > 0) {
for (var i = 0; i < specs.length; i++) {
var assert = specs[i];
var tcR = new RegExp(/TC[\d]+/);
var tc = assert.description.match(tcR);
if (!assert.failedExpectations.length) {
Passed = 1;
}
else {
assert.failedExpectations.forEach((expectation) => {
Message = expectation.message;
Stack = expectation.stack.split('\n')[1].trim();
})
Passed = 0;
}
if (tc != null) {
utility.TestDataManager.insertAutomationResults(tc[0], assert.description, Passed, process.env.testBuild,
'P', Message, Stack, 0, moment().utcOffset(config.get('settings.timeOffset')).format('YYYY-MM-DDTHH:mm:ss'), '')
.then(function (resp) {
resolve(Passed);
}, (err) => {
console.log('Posting to Database failed ', err);
reject(err);
});
} else {
console.log('no test case found for test: ' + assert.description + ' -- skipping');
reject(err);
}
}
}
}
}
catch (err) {
console.log('rejecting opening file');
reject(err);
}
});
})
}
If there is not exactly one suite in the obj, with exactly one spec, then your promise is either resolved not at all or multiple times.
Avoid wrapping too many things in the new Promise constructor - always promisify on the smallest possible level, and use promise chaining afterwards.
protractorParser.prototype.parseResults = function (fileName) {
return new Promise((resolve, reject) => {
console.log('In parseresults', fileName);
json.readFile(fileName, function (err, obj) {
if (err != null) {
console.log('error reading file', err);
reject(err);
} else {
resolve(obj);
}
});
}).then(function(obj) {
console.log('obj - ',obj);
var results = [];
for (var suite in obj) {
var specs = obj[suite].specs;
console.log('spec - ', specs);
for (let i = 0; i < specs.length; i++) {
const assert = specs[i];
const tcR = /TC[\d]+/;
const tc = assert.description.match(tcR);
let Passed = 1;
let Message = '';
let Stack = '';
if (assert.failedExpectations.length) {
const expectation = assert.failedExpectations[assert.failedExpectations.length-1];
Passed = 0;
Message = expectation.message;
Stack = expectation.stack.split('\n')[1].trim();
}
if (tc != null) {
const time = moment().utcOffset(config.get('settings.timeOffset')).format('YYYY-MM-DDTHH:mm:ss');
const promise = utility.TestDataManager.insertAutomationResults(tc[0], assert.description, Passed, process.env.testBuild, 'P', Message, Stack, 0, time, '');
results.push(promise.catch(err => {
console.log('Posting to Database failed ', err);
throw err;
}));
} else {
console.log('no test case found for test: ' + assert.description + ' -- skipping');
// I don't think you want to `throw err` here, right?
}
}
}
return Promise.all(results);
});
};
What I want to do is wait for the second promise to finish, concatenate the data i.e data = data.concat(items) and then increment the count making the loop run specified times. It's all written in AngularJS.
DataService.getSomeData().then(function(data) {
let count = 1;
while (count < 3) {
if (someCondition) { // It evaluates to true
// Second Promise
DataService.getUserData().then(function(items) {
data = data.concat(items); // --------> this should run before incrementing the count
});
count++;
}
$scope.myData = data;
}
});
Thanks!
Keep the api returning promises - its the easiest to handle and most predictable...
DataService.getSomeData()
.then(someData => {
let count = 1;
const promises = [];
while (count < 3) {
if (someCondition) { // It evaluates to true
promises.push(DataService.getUserData());
count++;
}
}
return $q.all(promises)
.then(data => data.reduce((memo, data) => memo.concat(data), someData));
})
.then(data => $scope.myData = data);
#Aleksey Solovey has already mentioned the solution which is to use $q.all(), there is another method of recursion which you can make use of.
DataService.getSomeData().then(function(data) {
getUserDataRecursion(data,0).then(result=>{
$scope.myData = result;
}).catch(error=>{
console.log("error handle ",error)
})
});
getUserDataRecursion(data,count){
return new Promise((resolve,reject)=>{
if(count<3){
if (someCondition){
DataService.getUserData().then((items) {
data = data.concat(items);
count++;
getUserDataRecursion(data,count),then(()=>{
resolve(data);
})
});
}else{
resolve(data);
}
}else{
resolve(data);
}
})
}