2017-08-03 59 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