javascriptreactjsfetch-apiwhen-js

How to fetch a list of objects and wait for them to finish?


I have a list of urls to follow and would like to store the result in an array. Current implementation is to use map to fetch and when.all to wait. Like below:

        const when = require('when');

        }).then((responseJson) => {
            return responseJson._embedded.leases.map(
                lease => fetch(lease._links.self.href, {headers: {'Access-Control-Expose-Headers': 'ETag'}}));
        }).then(leasePromises => {
            return when.all(leasePromises);
        }).then((leases) => {
            var obj = leases.toString();
            console.log("leasesJSON = " + obj);
            console.log("leases[0]0= " + leases[0]);
            console.log("leases[0]1= " + JSON.stringify(leases[0]));
            console.log("leases[0]2= " + leases[0].json());
            console.log("leases[0]3= " + JSON.stringify(leases[0].json()));
            this.setState({
                isLoading: false,
                leases: leases,
                attributes: Object.keys(this.schema.properties)
            });
        }).catch((error) => {
            console.error("loadDataFromServer error = " + error);
        });

But render() method complains that the 'leases' object is empty.

Tracing result:

leasesJSON = [object Response],[object Response]
leases[0]0= [object Response]
leases[0]1= {}
leases[0]2= [object Promise]
leases[0]3= {}

So my questions are:

  1. How to print out the promise and response information?
  2. is my way of fetching a list of objects correct?
  3. if not then how to correct them?

Solution

  • The response of a fetch API has the .json() method (as you seem to know), which is asynchronous; it returns a promise.
    Therefore, you must wait for it in order to have the actual objects returned from server; this is probably what's causing your problem.

    }).then((responseJson) => {
        return responseJson._embedded.leases.map(
            lease => fetch(lease._links.self.href, {headers: {'Access-Control-Expose-Headers': 'ETag'}}));
    }).then(leasePromises => {
        return when.all(leasePromises);
    }).then(leasesResponses => {
        return when.all(leasesResponses.map(response => response.json()));
    }).then(leases => {
      // leases is finally what you expected them to be!
    })
    

    The API is built that way because then you can act upon the response status/headers right away, without waiting for the response body to be fully downloaded/parsed.