ReactTS parallel api request calls for zip files download

Viewed 37

I am using React TS, with Nestjs as backend.

Context

I have a function downloadZip(csvProps): Input - Parameters for csv files and url for API requests; Output- Zip file containing 4 csv files

const downloadZip = async (csvProps: any, urlParams: any) => {
        let zip = new JSZip();

        let csv = zip.folder("csv");

        //English Data CSV
        let enDataBlob = await downloadCSV(`${ServerService.getUrl()}/fetchData`, urlParams,
            {...csvProps, filename: 'Data_en', columns: headers_data_en, wrapColumnChar: '"'})
        csv?.file('Data_en.csv', enDataBlob as Blob, {base64: true})

        //French Data CSV
        let frDataBlob = await downloadCSV(`${ServerService.getUrl()}/fetchData`, urlParams,
            {...csvProps, filename: 'Data_fr', columns: headers_data_fr, wrapColumnChar: '"'})
        csv?.file('Data_fr.csv', frDataBlob as Blob, {base64: true})

        //English Flow CSV
        let enFlowBlob = await downloadCSV(`${ServerService.getUrl()}/fetchFlow`, urlParams,
            {...csvProps, filename: 'Flow_en', columns: headers_flow_en, wrapColumnChar: '"'})
        csv?.file('Flow_en.csv', enFlowBlob as Blob, {base64: true})

        //French Flow CSV
        let frFlowBlob = await downloadCSV(`${ServerService.getUrl()}/fetchFlow`, urlParams,
            {...csvProps, filename: 'Flow_fr', columns: headers_flow_fr, wrapColumnChar: '"'})
        csv?.file('Flow_fr.csv', frFlowBlob as Blob, {base64: true})

        zip.generateAsync(({type: "blob"}))
            .then((content) => {
                saveAs(content, csvProps.filename)
            })
    }

The downloadCSV(url: string, urlParams: any, csvProps: any) function used above is simply to make an axios request to the backend, and return a csv blob generated from the response:

export const downloadCSV = async (apiURL: string, urlParams: any, csvProps: any) => {
    let csvBlob: Blob|undefined;
    let api = await axios.get(apiURL, {
        params: urlParams
      })
    .then(async (res) => {
        // handleCSV: Gets all CSV related data and returns a csv Blob
        csvBlob = await handleCSV({...csvProps, datas: res.data});
    })
    return csvBlob
}

Since I am using async-await, the api requests and consequent blob generation processes are happening sequentially, and the performance is being impacted.

Question

Is there a way I can make these processes parallel? I want all the files to be processed in parallel, and then eventually added to the zip.

1 Answers

Instead of awaiting each API call, you could do Promise.all(apiCalls) and await the result of that, letting the result be an array of values returned from the API. Something like

const downloadZip = async (csvProps: any, urlParams: any) => {
  let zip = new JSZip();

  let csv = zip.folder("csv");
  const apiCalls = [
    downloadCSV(`${ServerService.getUrl()}/fetchData`, urlParams,
      {...csvProps, filename: 'Data_en', columns: headers_data_en, wrapColumnChar: '"'}),
    downloadCSV(`${ServerService.getUrl()}/fetchData`, urlParams,
      {...csvProps, filename: 'Data_fr', columns: headers_data_fr, wrapColumnChar: '"'}),
    downloadCSV(`${ServerService.getUrl()}/fetchFlow`, urlParams,
      {...csvProps, filename: 'Flow_en', columns: headers_flow_en, wrapColumnChar: '"'}),
    downloadCSV(`${ServerService.getUrl()}/fetchFlow`, urlParams,
      {...csvProps, filename: 'Flow_fr', columns: headers_flow_fr, wrapColumnChar: '"'}),
  ];
  const [enDataBlob, frDataBlob, enFlowBlob, frFlowBlob] = await Promise.all(apiCalls);
  //English Data CSV
  csv?.file('Data_en.csv', enDataBlob as Blob, {base64: true})

  //French Data CSV
  csv?.file('Data_fr.csv', frDataBlob as Blob, {base64: true})

  //English Flow CSV
  csv?.file('Flow_en.csv', enFlowBlob as Blob, {base64: true})

  //French Flow CSV
  csv?.file('Flow_fr.csv', frFlowBlob as Blob, {base64: true})

  zip.generateAsync(({type: "blob"}))
    .then((content) => {
      saveAs(content, csvProps.filename)
    })
}
Related