RyanP13
RyanP13

Reputation: 7743

Axios POST requests return empty array when using Promise.all

I do not get any statuses of the promises in my requests array when resolving with Promise.all.

What am I doing wrong here as I thought that using axios post method would return a promise?

  const doUpload = async (fileList: FileList) => {
    const requests: Array<void | AxiosResponse<any>> = [];

    Array.from(fileList).forEach(async file => {
      const formData = new FormData();
      const blob = new Blob([file]);
      formData.append(file.name, blob);

      requests.push(
        await axios
          .post(
            'https://jsonplaceholder.typicode.com/posts',
            {
              ...formData,
            },
            {
              headers: {
                'Content-Type': 'multipart/form-data',
              },
              onUploadProgress: (progressEvent: ProgressEvent) =>
                handleUploadProgress(progressEvent, file.lastModified),
            }
          )
          .catch(error => {
            handleUploadError(file.lastModified);
          })
      );
    });

    try {
      const data = await Promise.all(requests);
      console.dir(data);
    } catch (error) {
      console.log(error);
    }
  };

Upvotes: 0

Views: 916

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1074138

Jeremy's right that you have unnecessary awaits in your code, but the primary problem is that you're hiding promise rejection by putting a catch handler on the promise from post and then letting that handler complete without either throwing an error or returning anything. That turns rejection into fulfillment with the value undefined.

Remove the catch handler (probably) or have it return something that you can use to know the post failed.


FWIW, here's an example doing the above and using Array.from's mapping feature (since you're doing a mapping operation); see comments:

const doUpload = async (fileList: FileList) => {
  // Use `map`
  const requests = Array.from(fileList, file => {
    const formData = new FormData();
    const blob = new Blob([file]);
    formData.append(file.name, blob);

    // No need for `await` here
    return axios.post(
      'https://jsonplaceholder.typicode.com/posts',
      {
        ...formData,
      },
      {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
        onUploadProgress: (progressEvent: ProgressEvent) =>
          handleUploadProgress(progressEvent, file.lastModified),
      }
    );
    // No `.catch` here (or have one, but make it return something useful
  });

  try {
    const data = await Promise.all(requests);
    console.dir(data);
  } catch (error) {
    console.log(error);
  }
};

If you need to call handleUploadError somewhere in there, you might consider using Promise.allSettled (relatively new) rather than Promise.all and then calling that for any rejected promises in the array it gives you.


...when resolving with Promise.all.

Just a side note: Using Promise.all doesn't "resolve" the promises you pass into it. It just observes what happens with them. The promises will settle however they're going to settle whether you use Promise.all or not.

Some promise terminology that may be helpful:

  • fulfill - To change a promise state from pending to fulfilled with a specific fulfillment value
  • reject - To change a promise state from pending to rejected with a specific rejection reason
  • resolve - To determine the eventual outcome of a promise, either directly (by fulfilling or rejecting it) or indirectly (by making its outcome depend on the outcome of another promise)

Upvotes: 3

Jeremy Thille
Jeremy Thille

Reputation: 26360

You are pushing resolved Promises to your array (requests.push(await axios.post())). Just push Promises without awaiting them(requests.push(axios.post())). Then Promise.all can do its job.

const doUpload = async(fileList: FileList) => {
    const requests: Array < void | Promise<any> > = [];

    Array.from(fileList).forEach( file => {
        const formData = new FormData();
        const blob = new Blob([file]);
        formData.append(file.name, blob);

        requests.push(axios.post(/* ... */ ));
    });

    try {
        const data = await Promise.all(requests);
        console.dir(data);
    } catch (error) {
        console.log(error);
    }
};

Upvotes: 2

Related Questions