2017-08-03 70 views
4

我想调用一个for循环内的函数,问题是函数在循环完成后调用。Node.js呼叫循环内的回调函数

以下面作为一个例子,其打印到控制台:
here1
here1
here2
here2

代替
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 
     }); 
     }); 
    }); 
    }); 
}); 

我该如何解决这个问题?

请让我知道如果我需要提供更多的信息


下面是完整的代码:

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); 
       } 
      }); 
      } 
     }); 
     }); 
    }); 
    } 
} 

这些回调函数:

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); 
    }); 
} 

我的目标在循环结束后返回failureList阵列compliance ar光做

我发现了一个类似的问题here但不能肯定是否会在我的情况下工作,我真的不知道如何实现承诺

+4

发生这种情况的原因是您的内部调用(其中'this2'已打印)运行_asynchronously_。这意味着首先执行'here1'的所有过程,每个过程调度'here2'的未来执行,然后执行所有计划执行。这就是你所看到的。 – slezica

+0

我认为这是因为你期待你的程序同步执行,而回调异步工作。看看异步/等待,如果你希望它按照你写的顺序等待方法。 – haakym

+0

@slezica我是node.js的新手,基于我的代码的例子会帮助我很多。 – Valip

回答

-1

for循环执行范围顺序内的语句。但它不会等待函数调用完成,而是继续执行下一个语句(即异步工作)。这就是为什么结果如此。您可以使用Promises或使用async模块使其同步工作。

由于不清楚你打算在函数调用中执行什么以及你想要执行的语句,所以我无法建议其中的任何一个。 。 asyn.each通常是使for循环同步执行的首选。当你想等待函数完成执行然后执行操作时使用promise。如果你想这样做的顺序使用async.eachOfSeries你可能想看看他们的文档

Promises|MDN

async.each

谢谢Ragul

-1

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 
    }) 

如果你想优化的过程看看async.parallel