I am trying to call a function inside a for
loop and the problem is that the function is called after the loop was finished.
Taking the below as an example, it prints to the console:
here1
here1
here2
here2
Instead of
here1
here2
here1
here2
report.forEach(item => {
item.runs.forEach(run => {
waComplianceBusiness(req, run.id, (err, res) => {
const compliance = res.data.overviews[0].compliance;
var failureList = [];
compliance.forEach((rule, index) => {
console.log('here1');
waRuleOverview(req, run.id, rule.id, (err, res) => {
console.log('here2');
// handle the response
});
});
});
});
});
How can I fix this?
Please let me know if I need to provide additional information
Here is the complete code:
export default (req, callback) => {
const report = req.body.webAudits;
if(report.length > 0) {
report.forEach(item => {
item.runs.forEach(run => {
waComplianceBusiness(req, run.id, (err, res) => {
const compliance = res.data.overviews[0].compliance;
if(compliance) {
var failureList = [];
compliance.forEach((rule, index) => {
if(rule.pagesFailed > 0) {
waRuleOverview(req, run.id, rule.id, (err, res) => {
const failedConditions = res.data.failedConditions;
const ruleName = res.data.ruleName;
failedConditions.forEach((condition, failedIndex) => {
const request = {
itemId: condition.conditionResult.id,
itemType: condition.conditionResult.idType,
parentId: condition.conditionResult.parentId,
parentType: condition.conditionResult.parentType
}
const body = {
runId: run.id,
ruleId: rule.id,
payload: request
}
waConditionOverview(req, body, (err, res) => {
const description = res.data.description;
const conditionValues = res.data.conditionValues[0];
var actualValue = conditionValues.value;
if(actualValue == "") {
actualValue = 'empty';
}
if(description.idType == "variable") {
var failureObj = {
ruleName: ruleName,
expected: description.name + ' ' + description.matcher + ' ' + description.expected[0],
actual: description.name + ' ' + description.matcher + ' ' + actualValue
};
}
else if(description.idType == "tag") {
var failureObj = {
ruleName: ruleName,
expected: description.name + '\n' + description.matcher,
actual: actualValue
};
}
failureList.push(failureObj);
});
});
});
}
if(key + 1 == compliance.length) {
console.log(failureList);
}
});
}
});
});
});
}
}
These are the callback functions:
export function waComplianceBusiness(req, runId, callback) {
const apiToken = req.currentUser.apiToken;
const payload = {
'Authorization': 'api_key ' + apiToken
}
const options = {
'method': 'get',
'gzip': true,
'headers': payload,
'content-type': 'application/json',
'json': true,
'url': 'api_url'
}
request(options, (error, response, body) => {
callback(null, body);
});
}
export function waRuleOverview(req, runId, ruleId, callback) {
const apiToken = req.currentUser.apiToken;
const payload = {
'Authorization': 'api_key ' + apiToken
}
const options = {
'method': 'get',
'gzip': true,
'headers': payload,
'content-type': 'application/json',
'json': true,
'url': 'api_url'
}
request(options, (error, response, body) => {
callback(null, body);
});
}
export function waConditionOverview(req, body, callback) {
const apiToken = req.currentUser.apiToken;
const payload = {
'Authorization': 'api_key ' + apiToken
}
const options = {
'method': 'post',
'gzip': true,
'headers': payload,
'body': body.payload,
'content-type': 'application/json',
'json': true,
'url': 'api_url'
}
request(options, (error, response, body) => {
callback(null, body);
});
}
My goal is to return the failureList
array after the loop over the compliance
array is done
I found a similar question here but not sure if that would work in my case and I don't really know how to implement the promises
The for loop executes the statements inside the scope sequentially. But it does not wait for the the function calls to complete, it continues with the next statement(ie works asynchronously). That is why the result is as such. You can make it work synchronously using Promises
or by using the async
module.
As it is not clear what you are going to perform in the function call and what you want the statements to do, I am not able to suggest either of which. . asyn.each
is usually preferred for making the for loop execute synchronously. And promises are used when you want to wait for the function to finish executing and then perform operation. You might want to look at their documentation
Thank you, Ragul
If you want to do it in sequence use async.eachOfSeries
async.eachOfSeries(report, function(item, index, eachOfCallback1){
async.eachOfSeries(item.runs, function(run, index, eachOfCallback2){
waComplianceBusiness(req, run.id, (err, res) => {
var failureList = [];
async.eachOfSeries(compliance, function(rule, index, eachOfCallback3){
console.log('here1');
waRuleOverview(req, run.id, rule.id, (err, res) => {
console.log('here2');
return eachOfCallback3(err);
});
}, function(err){
if(err)
return eachOfCallback2(err);
else return eachOfCallback2();
});
});
}, function(err){
if(err)
return eachOfCallback1(err);
else return eachOfCallback1();
})
}, function(err){
// handle final response
})
If you want to optimise the process take a look at async.parallel
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.