0

I've been struggling to figure out how to do this for the past two hours. But I can't seem to get the Promise to wait for my searchFacesFunc to complete before it solves. What is the correct way to do so?

async function searchFacesFunc(faceId){
     var searchFacesParams = {
      CollectionId: "my-collection", 
      FaceId: faceId,
      FaceMatchThreshold: 80, 
      MaxFaces: 10
     };
     await rekognition.searchFaces(searchFacesParams, function(err, data) {
     if(err){
        throw err;
     }else{
        var matching_percent = data.FaceMatches[0].Similarity;   
        console.log('Matching Percent: ' + matching_percent);
     }
   });
 }

 return new Promise((resolve, reject) => {
     rekognition.indexFaces(indexParams, function(err, data) {
             if(err){
                 throw err;
             }else{
                 const faceRecords = data.FaceRecords;
                 for(let i = 0; i < faceRecords.length; i++){
                     var faceId = faceRecords[i].Face.FaceId;
                     console.log('FaceId: ' + faceId);
                     searchFacesFunc(faceId); //The promise is finished before these multiple functions finish
                 }
                resolve(null, 'success');
             }
     });
 });
DIRTY DAVE
  • 2,523
  • 2
  • 20
  • 83
  • 1
    Please don't ever write a single line of `if (err) throw err` inside a plain asynchronous callback. At worst, it makes your program crash. At best, you silently eat the error and abort the operation and wonder why nothing works. Always, log the error and always write real error handling. You cannot catch that error elsewhere in your program unless the async API explicitly passes the error to something you called higher up (which is almost never the case). – jfriend00 Apr 02 '20 at 00:41
  • noted for next time thx – DIRTY DAVE Apr 02 '20 at 00:43
  • 1
    FYI, in your second example where you are manually promisifying, you can replace `if (err) throw err` with `if (err) {reject(err);} else { ... }`. Not the subject of your question, but that would be decent error handling. – jfriend00 Apr 02 '20 at 00:45
  • Does this answer your question? [Asynchronous Process inside a javascript for loop](https://stackoverflow.com/questions/11488014/asynchronous-process-inside-a-javascript-for-loop) – Dan O Apr 02 '20 at 00:49
  • there are many, many Stack Overflow questions regarding calling async JavaScript functions inside of loops. which of them did you research and why did they not solve your specific problem? – Dan O Apr 02 '20 at 00:51

1 Answers1

0

If the rekognition.indexFaces function accepts an asynchronous callback, you can solve this issue easily:

  return rekognition.indexFaces(indexParams, async (err, data) => {
    if (err) {
      throw err;
    } else {
      const faceRecords = data.FaceRecords;
      for (let i = 0; i < faceRecords.length; i++) {
        var faceId = faceRecords[i].Face.FaceId;
        console.log("FaceId: " + faceId);
        await searchFacesFunc(faceId); // Await the promise
      }
      return "success";
    }
  });
};

However, if this is not the case, you can still solve this the following way:

  1. Use util.promisify to "promisify" the rekognition.indexFaces function
  2. Construct a recursive callback function that only resolves the original promise you constructed when it executed faceRecords.length times.
derbenoo
  • 303
  • 1
  • 2
  • 10
  • You can't just not pass the callback and `await`. The function in question has to specifically return a promise if no callback is supplied. Some functions do implement that, but this would only work if that was the case. Your answer says "if the function accepts a callback". Well, we already know it accepts a callback. The question is whether it returns a promise or not. – jfriend00 Apr 02 '20 at 00:40