Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do multiple .fetch() promises

I want to fetch multiple images and turn them in blob. I'm a newbie about promises, I've tried but I can't get through.

Here below, a single .fetch() promise

fetch('http://cors.io/?u=http://alistapart.com/d/_made/d/ALA350_appcache_300_960_472_81.jpg')
    .then(function(response) {
        return response.blob();
    })
    .then(function(myBlob) {
        var objectURL = URL.createObjectURL(myBlob);
        document.getElementById('myImage').src = objectURL;
    });

Now multiple .fetch() promise (don't work)

var promises = [];

for (var i = values.length - 1; i >= 0; i--) {
    promises.push(fetch(values[i]));
}

Promise
    .all(promises)
    .then(function(response) {
        for (var i = response.length - 1; i >= 0; i--) {
            return response[i].blob();
        }
    })
    .then(function(blob) {
        console.log(blob.length); //undefined !!!
        for (var i = blob.length - 1; i >= 0; i--) {
            console.log(blob[i]);
            lcl_images[i].value = URL.createObjectURL(blob[i]);
            document.getElementById(lcl_images[i].id).src = objectURL;
        }
    })
    .catch(function(error) {
        console.log(error);
    });
like image 993
FrancescoN Avatar asked Jun 24 '16 15:06

FrancescoN


People also ask

Does fetch use promise?

fetch() The global fetch() method starts the process of fetching a resource from the network, returning a promise which is fulfilled once the response is available. The promise resolves to the Response object representing the response to your request.

How do you handle multiple fetch requests?

To do multiple fetch requests in parallel, we can use the all() method from the global Promise object in JavaScript.

What is fetch () in JavaScript?

The fetch() method in JavaScript is used to request data from a server. The request can be of any type of API that return the data in JSON or XML. The fetch() method requires one parameter, the URL to request, and returns a promise.


2 Answers

It is a general rule that a wholly synchronous intermediate step in the success path of a promise chain can be amalgamated with the next step, allowing one then() to be omitted from the chain.

There is actually a proviso on that statement, involving intermediate catches, but it will suffice for this answer.

So, if the .blob() method is geuinely synchronous (it returns a value), only one .then() is required, not two.

Here are two approaches, both of which exploit Array.prototype.map(), and both should work (though they will differ under error conditions):

1. Simple .map() with detail in Promise.all()

var promises = values.reverse().map(fetch); // you may need .reverse(), maybe not. I'm not 100% sure.

return Promise.all(promises).then(function(responses) {
    responses.forEach(function(r, i) {
        var imageObj = lcl_images[i],
            element = document.getElementById(imageObj.id);
        imageObj.value = URL.createObjectURL(r.blob());
        if(element) { //safety
            element.src = imageObj.value;
        }
    });
    return responses; // here, return whatever you want to be made available to the caller.
}).catch(function(error) {
    console.log(error);
});

If you prefer, you can write :

return Promise.all(values.reverse().map(fetch)).then(function(responses) {
    // ...
});

2. Detail in .map() followed a simple Promise.all()

var promises = values.reverse().map(function(val, i) {
    return fetch(val).then(function(result) {
        var imageObj = lcl_images[i],
            element = document.getElementById(imageObj.id);
        imageObj.value = URL.createObjectURL(result.blob());
        if(element) { //safety
            element.src = imageObj.value;
        }
        return result; // here, return whatever you want to be made available to the caller.
    });
});

return Promise.all(promises).catch(function(error) { // return a promise to the caller
    console.log(error);
}); 

Notes:

  • (1) will fail completely if any one fetch() fails.
  • (2) will perform all the imageObj.value ... and element.src = ... stuff for all successful fetches even if one or more fetch()... fails. Any single failure will cause Promise.all(promises) to return a rejected promise.
  • (1) or (2) may be more appropriate depending on what you want.
  • There are other error handling possibilities.
  • If neither approach works, then the most reasonable explanation would be that the .blob() method returns a promise, not a value.
like image 106
Roamer-1888 Avatar answered Sep 21 '22 23:09

Roamer-1888


You are returning from the then handler after first response, instead what you need to do is to return the list of blobs:

Promise
.all(promises)
.then(function(response) {
    // CHANGED HERE
    var blobPromises = [];
    for (var i = response.length - 1; i >= 0; i--) {
        blobPromises.push(response[i].blob());
    }
    return Promise.all(blobPromises);
})
.then(function(blob) {
    console.log(blob.length);
    for (var i = blob.length - 1; i >= 0; i--) {
        lcl_images[i].value = URL.createObjectURL(blob[i]);
        document.getElementById(lcl_images[i].id).src = objectURL;
    }
})
.catch(function(error) {
    console.log(error);
});
like image 41
Łukasz Avatar answered Sep 24 '22 23:09

Łukasz