0

I have been trying to find a solution to a problem regarding an asynchronous method, I have tried various types of loops, using async/await, as well as Promisies, but none I try seem to work for me.

So I have my first method:

const postApplication = async (params...): Promise<DocumentReference> => {
   const formData = await prepareData(someParams...)

   {rest of method...}
}

I then have my prepareData function, which I believe is where my issue:

P.S. I am only keeping the information that I think is necessary to make it simpler.

const prepareData = async (params...) => {

    const formData = new FormData();

    {some synchronous code...}

    for await (const field of allCustomFields) {
      if (field.identifier === someProperty) {
        formData.append("fieldName", field)
      } else {
        for await (const value of field.value) {
           const storage = getStorage();
          if (value) {
            const fileInfo = value as FileValue;
            const imageName = fileInfo.firebaseStoragePath
              ?.split("mutable/")
              .pop();
            getDownloadURL(
              ref(storage, `users/${user?.id}/mutable/${imageName}`)
            ).then((url) => {
              const xhr = new XMLHttpRequest();
              xhr.responseType = "blob";
              xhr.onload = (event) => {
                const file = xhr.response;
                const extension = file.type.split("image/").pop();
                formData.append(
                  "filesToUpload",
                  file,
                  `${field.identifier}-${docCounter}.${extension}`
                );
                docCounter += 1;
              };
              xhr.open("GET", url);
              xhr.send();
            });
          }
        }
      }
    }
   return formData;
}

So the problem I am having, is that formData is being returned before the files I am retrieving from Firestore have been appended to formData. I have tried each of the loops in a Promise and then calling await Promise.all(nameOfConst) before returning formData, but none seem to work.

I appreciate anybody that can offer some help,

Thanks

TreyCollier
  • 181
  • 1
  • 12
  • 2
    Don't use `for await` unless you are iterating an AsyncIterator. – Bergi Dec 17 '21 at 12:54
  • 2
    The problem comes from using `.then()` instead of `await` on the `getDownloadURL()` promise, and of course from using `XMLHttpRequest` [without a promise](https://stackoverflow.com/q/30008114/1048572) or instead of `fetch`. – Bergi Dec 17 '21 at 12:56
  • Hi @Bergi I have tried just a regular `` for (const...)``, ``.forEach`` and ``.map``, this is just one of the ways I have tried. – TreyCollier Dec 17 '21 at 12:56
  • @Bergi Ok, so I replaced the ``.then()`` with an ``await`` for the ``getDownloadURL()``, and I then replaced the ``XMLHttpRequest`` with a ``fetch``, but the response type of the fetch was wrong, and it didn't respond with the file, I then went back to the ``XMLHttpRequest``, and it only appended 1 of my files to ``formData`` before returning ``formData``. – TreyCollier Dec 17 '21 at 13:24
  • Since you're clearly just making wild guesses as to how to do this asynchronous programming and where/when to use `await`, I'd suggest you go back a few steps and read some basic tutorials on how async and await work. It would be best if you learned the fundamentals rather than just stab at solutions to this current problem. – jfriend00 Dec 17 '21 at 13:58
  • One starting point with this current problem is to avoid mixing asynchronous operations using plain callbacks (like XMLHttpReqest) with promises. If you're using any promises, then ALL your asynchronous operations need to be promise-based so you can use the promise tools to control the flow. In this case, you can switch to `fetch()` and use promises. – jfriend00 Dec 17 '21 at 13:59
  • Also `.forEach()` is not promise-aware so it will usually not be useful with an asynchronous operation in loop. A `for` loop will be your best option for sequenced asynchronous operations and `.map()` can be used in combination with `Promise.all()` if you're trying to run a loop of asynchronous operations in parallel and collect all the results together. – jfriend00 Dec 17 '21 at 14:00
  • 1
    @Bergi Hi again, thanks a lot for your help. So replacing the ``.then()`` for the ``getDownloadURL()`` and wrapping the ``XMLHttpRequest`` in a ``Promise`` did the trick. – TreyCollier Dec 17 '21 at 15:33
  • @jfriend00 I appreciate what you are saying, and you are right. I am not all that confident regarding asynchronous programming in React Native/JS/TS on the backend, I am predominantly a Scala dev on the backend. Anyway, thanks for the tip regarding ``.forEach``, this was my first approach, and I did read up earlier today about this point. – TreyCollier Dec 17 '21 at 15:35
  • @TreyCollier Glad to have helped, you might want to [write an answer](https://stackoverflow.com/help/self-answer) with your working code – Bergi Dec 17 '21 at 16:38

0 Answers0