Home > OS >  How to return an async map function in the correct order?
How to return an async map function in the correct order?

Time:11-17

I have this function right here:

const uploadedFiles: string[] = [];
await Promise.all(
   selectedImageUrls.map(async (selectedUrl) => {
       const fileName = selectedUrl.startsWith("data:image/png")
          ? `${id}-${Date.now()}.png`
          : `${id}-${getFileNameFromUrl(selectedUrl)}`;
       const fileData = await fetch(selectedUrl).then((x) => x.arrayBuffer());
       const newUrl = await uploadInvoiceFile(userId, fileName, fileData);
       uploadedFiles.push(newUrl);
   })
);

So basically I have an array called selectedImageUrls and I map through this array to execute some async functions so I put this map inside of a Promise.all() and on the last line, you can see that in every map, I push the result of the async functions into an array called uploadedFiles, however, this result is not in the same order as the original array (selectedImageUrls). How can I modify this code so that the order will be exactly the same?

CodePudding user response:

Promise.all will return requests in the same order you created the map. But the order things get completed could be out of order.

So all you need to do is get the results from Promise.all. eg..

const uploadedFiles = await Promise.all(
   selectedImageUrls.map(async (selectedUrl) => {
       const fileName = selectedUrl.startsWith("data:image/png")
          ? `${id}-${Date.now()}.png`
          : `${id}-${getFileNameFromUrl(selectedUrl)}`;
       const fileData = await fetch(selectedUrl).then((x) => x.arrayBuffer());
       const newUrl = await uploadInvoiceFile(userId, fileName, fileData);
       return newUrl;
   })
);

Ps. seen as your using Typescript, the nice thing is that uploadedFiles will implicitly be of type string[] too, assuming newUrl is a string of course..

Also a little tip, if last thing you do inside an async function is return a promise, you can skip the temporary variable and await.

eg.

const newUrl = await uploadInvoiceFile(userId, fileName, fileData);
return newUrl;

Can be simplified to ->

return uploadInvoiceFile(userId, fileName, fileData);

CodePudding user response:

in every map, I push the result of the async functions into an array called uploadedFiles

Just don't do that. Promise.all will already create an array with all the promise results, use that:

const uploadedFiles: string[] = await Promise.all(
    selectedImageUrls.map(async selectedUrl => {
        const fileName = selectedUrl.startsWith("data:image/png")
          ? `${id}-${Date.now()}.png`
          : `${id}-${getFileNameFromUrl(selectedUrl)}`;
        const x = await fetch(selectedUrl)
        const fileData = await x.arrayBuffer();
        return uploadInvoiceFile(userId, fileName, fileData);
//      ^^^^^^
    })
);
  • Related