0

I'm getting a headache from trying to come up with a solution, and I hope that someone here can solve my problem.

I am trying to create a program that will do a loop for a number of audio files, using NodeJS:

  1. Access audio file from source.
  2. Send audio file to outside API for treatment (this part is already handled).
  3. Obtain the answer to the audio file treatment
  4. Display the answer

The API cannot work on 2 or more audios at the same time because it mixes them up and returns incorrect results, so the audio list has to be handled sequentially (so, it does steps 1-5 for audio_1, then steps 1-5 for audio_2, etcetera).

I can do the loop just fine, but due to how Promises work, what the program actually does is this:

  1. Do step 1 for audio_1.
  2. Get a Promise to do step 2 for audio_1.
  3. Do step 1 for audio_2.
  4. Get a Promise to do step 2 for audio_2...
  5. Once it gets all the Promises, it listens in until all the the Promises are resolved.

And this messes things up due to the above mentioned problem.

Here's the code I have right now:

async function myFunction(client){
  ...
  const fileC = database()
  const vars = {"variable":"my_variable"}
  const url = "my_url"

  let result
  await fileC.find({}).forEach(f=>fileList.push(f))
  for (const f of fileList){
    await https.get(f.file_location,function(res){
      let form = new FormData()
      Object.keys(vars).forEach(key=>form.append(key,vars[key]))
      form.append("file",res,f.file_name)
      axios.post(url,form,{headers:form.getHeaders(),maxBodyLength:Infinity}).then((response)=>{
        console.log(response.data.val)
      })
    })
  }
}

My only obstacle is ensuring that the for loop will not move to one cycle until the previous one has finished - once I get that, then my full program should work.

Any ideas?

EDIT: modified a bunch of things because I realized I could skip them.

EDIT 2: just to point out. The objective is that the for loop will not go to do one cycle until the previous one is finished. I tried to do this using a while loop to block the cycle, but it didn't work, either.

7
  • Does this answer your question? Using async/await with a forEach loop Commented Sep 13, 2021 at 14:59
  • Short answer: use for...of instead of Array.prototype.forEach Commented Sep 13, 2021 at 15:00
  • Sorry, I added just that, but it still doesn't work Commented Sep 13, 2021 at 15:10
  • Why are you mixing http.get and axios.post? Axios has promise support. Commented Sep 13, 2021 at 17:28
  • 1
    Unless you promisfy http.get, it does not return a promise and the await there is meaningless. That is the point of my question. If the await does not await, the for...of also does not wait on each iteration. Commented Sep 14, 2021 at 11:14

2 Answers 2

2

The https.get function, according to its documentation, does not return a promise.

You can, however, wrap it inside of a function that does return a promise like the following with promiseHttpsGet

const promiseHttpsGet = (url) =>
  new Promise((resolve, reject) => {
    https
      .get(url, (res) => {
        resolve(res);
      })
      .on("error", (er) => {
        reject(er);
      });
  });

async function myFunction(client) {
  const fileC = database();
  const vars = { variable: "my_variable" };
  const url = "my_url";

  let result;

  await fileC.find({}).forEach((f) => fileList.push(f));

  for (const f of fileList) {
    // The helper function returns a promise so you can await that
    const res = await promiseHttpsGet(f.file_location);

    let form = new FormData();

    Object.keys(vars).forEach((key) => form.append(key, vars[key]));
    form.append("file", res, f.file_name);

    // You can await the axios response as well instead of using .then
    const axiosResponse = await axios.post(url, form, {
      headers: form.getHeaders(),
      maxBodyLength: Infinity,
    });

    console.log(response.data.val);
  }
}
Sign up to request clarification or add additional context in comments.

3 Comments

My problem is not with https.get - that works just fine. What I need is so it will wait until it does everything in the callback before it continues doing the same with the rest. In fact, making it so the get returns a promise is not something I want (because it would create a promise for all the files and begin running them all).
@MikelDeepLearner I don't think you understand how promises work. If you need to wait for the http get to complete, and the completion is the execution of a callback, converting to a promise for that one call allows the caller to wait on that one promise. before moving on to other code.
@crashmstr OK, you made me realize what was wrong with that comment, and it works now. Thanks!
0

OK, I managed to come up with a solution, based on what @crashmstr pointed out about the use of promises. I separated the function for sending the audio from the rest and it worked.

async function getData(f,fileC){
  const vars = {"variable":"my_variable"}
  const url = "my_url"
  return new Promise(function(resolve,reject){
    https.get(f.file_location,function(res){
      let form = new FormData()
      Object.keys(vars).forEach(key=>form.append(key,vars[key]))
      form.append("file",res,f.file_name)
      axios.post(url,form,{headers:form.getHeaders(),maxBodyLength:Infinity}).then((response)=>{
        let value = response == "" //placeholder for actual work
        let update = {"res":response,"value":value}
        resolve(update)
      })
    })
  })
}

async function myFunction(client){
  const fileC = database()
  let result
  await fileC.find({}).forEach(f=>fileList.push(f))
  for (const f of fileList){
    result = await getData(f,fileC)
    await fileC.updateOne(f,{$set:result["update"]})
  }
}

I admit that my experience with promises is quite limited, but this does, at least, serve as a good lesson.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.