简体   繁体   中英

Node.js callback after for loop

I am new to Node and am trying to append data in a for loop of API calls but am running into challenges with the asynchronous nature of Node.

function emotionsAPI(data, next){
    for(var url in data) {
        if(data.hasOwnProperty(url)) {
            request({
            method: 'POST',
            url: 'https://api.projectoxford.ai/emotion/v1.0/recognize',
            headers: {
                "Content-Type": 'application/json',
                "Ocp-Apim-Subscription-Key": keys.emotion_key
            },
            body: "{\"url\" : \"" + url + "\"}"
            }, function (error, response, body){
                var emotions = JSON.parse(body)
                if (emotions.length > 0){
                    var scores = emotions[0].scores;
                    console.log("scores found");
                    console.log(scores.anger);
                    data[url].anger = scores.anger;
                }
            })
        }
    }
    next(data);
}

function faceAPI(data){
    console.log("HELP");
    console.log(data);
}

emotionsAPI(data, faceAPI);

The console.log in the faceAPI function prints to the console properly but does not reflect the changes that the for loop should have made. I tried using async.forEachOf but the console just seemed hang forever.

I believe you a trying call url request as synchronous way, but the results works, as you metioned, in asynchronous.

I believe this library can be good for you: async

Also, you can write your method as a recursive style. But this is not a good practice. You should change this method to being called at once, and then, pass the faceAPI(data) method inside the callback post method.

One one iteration of the for look goes, it does not wait till the callback is resolved before it starts the next. Thus is finishing the forloop and returning to the next function possibly before any of the requests have finished.

If you are okay with the calls happeneing one after another you can place them in a recursive function and make the next request after the previous one is finished.

var arr = Object.keys(data); // store the key names in an array

emotionsAPI(0, data, faceAPI)

function emotionsAPI(data, index, next) {
  if(index < arr.length) {
    request({
      method: 'POST',
      url: 'https://api.projectoxford.ai/emotion/v1.0/recognize',
      headers: {
        "Content-Type": 'application/json',
        "Ocp-Apim-Subscription-Key": keys.emotion_key
      },
      body: "{\"url\" : \"" + url + "\"}"
    }, function (error, response, body){
      var emotions = JSON.parse(body)
      if (emotions.length > 0){
        var scores = emotions[0].scores;
        console.log("scores found");
        console.log(scores.anger);
        data[arr[index]].anger = scores.anger;
      }
      emotionsAPI(data, ++index, next);
    })
  } else {
    next(data);
  }
}

Otherwise if you would like the requests to still be made concurrently I would recomend looking into Promises . Specifically Promise.all .

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM