Search code examples
javascriptajaxasynchronousfetch-api

Multiple fetch request in a row


For a project, I have to generate a PDF that lists the vehicles in a DB. To do this, I use the JSPDF library.

1st step: I get data from a DB (via asynchronous requests on an API) and images on a server that I store in an Array.

2nd step: I call a function that generates the PDF with JSPDF. The problem is that I need to have all my data retrieved before calling my generatePDF function otherwise the fields and images are empty because they have not yet been retrieved from the DB or the server.

A solution I found is to use the setTimeout function to put a delay between each call. However, this makes the code very slow and inflexible because you have to change the timeout manually depending on the number of data and images to retrieve. Moreover, it is impossible to determine exactly how long it will take to retrieve the data, especially since this can vary depending on the state of the network, so you have to allow for a margin which is often unnecessary.

Another solution is to use callbacks or to interweave fetch / ajax calls with .then / .done calls, but this becomes very complicated when it comes to retrieving the images since they are retrieved one by one and there are more than a hundred of them.

What would be the easiest way to do this in a clean and flexible way? Thanks for your help and sorry for the long text, I tried to be as clear as possible :)


Solution

  • To do a series of asynchronous things in order, you start the next operation in the fulfillment handler of the previous operation.

    An async function is the easiest way:

    async function buildPDF() {
        const response = await fetch("/path/to/the/data");
        if (!response.ok) {
            throw new Error(`HTTP error ${response.status}`);
        }
        const data = await response.json(); // Or `.text()` or whatever
        const pdf = await createPDF(data);  // Assuming it returns a promise
        // ...
    }
    

    If you can't use async functions in your environment and don't want to transpile, you can write your fulfullment handlers as callbacks:

    function buildPDF() {
        return fetch("/path/to/the/data")
        .then(response => {
            if (!response.ok) {
                throw new Error(`HTTP error ${response.status}`);
            }
            return response.json(); // Or `.text()` or whatever
        })
        .then(data => createPDF(data))
        .then(pdf => {
            // ...
        });
    }
    

    Note that I'm returning the result of the chain, so that the caller can handle errors.