3

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?
gustavohenke
  • 40,997
  • 14
  • 121
  • 129
LOUDKING
  • 301
  • 1
  • 13
  • Your sample is incomplete. Where is this code located within your component? If your render method is saying that the lease object is empty then your render method is being called before the fetch is complete. I also strongly advise against adding so much logic within the component itself, keep the component as dumb as possible. I would not use the component until the fetch successfully completes. Makes debugging and unit testing a lot simpler, and your component more reusable. – SummaNerd Sep 18 '17 at 00:54
  • `}).then(leasePromises => { return when.all(leasePromises); })` looks very wrong, given that `leasePromises` is the result of a `fetch` (assuming of course that the `fetch` in question is the same as or equivalent to the `fetch` you see in browsers these days – Jaromanda X Sep 18 '17 at 00:59

1 Answers1

3

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.

gustavohenke
  • 40,997
  • 14
  • 121
  • 129