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('/?u=.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);
});
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./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);
});
Share
Improve this question
edited Jun 24, 2016 at 15:35
FrancescoN
asked Jun 24, 2016 at 15:02
FrancescoNFrancescoN
2,17612 gold badges36 silver badges48 bronze badges
5
-
So what does the
.blob()
method return, ablob
or apromise
? – Roamer-1888 Commented Jun 25, 2016 at 9:46 -
.blob() returns a blob(), but if you're doing multiple promise, you have to
return Promise.all(blobs)
in.then(response)
. After this, in.then(blob)
-> blob is array of blob objects – FrancescoN Commented Jun 25, 2016 at 10:32 -
OK, so if
.blob()
is synchronous, then you don't need two .thens.Promise.all(promises).then(function(responses) {...}).catch(...);
will do the job without ever needing to create an array of blobs. – Roamer-1888 Commented Jun 25, 2016 at 11:00 -
if you try yourself this won't work, I'm a newbie about promise. I've tried several times doing what you said, but you have to return the promise
response[i].blob()
and in the next.then
you'll have the blob object. – FrancescoN Commented Jun 26, 2016 at 10:10 - 1 I'll write an answer for you. – Roamer-1888 Commented Jun 26, 2016 at 11:50
2 Answers
Reset to default 7It 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 pletely if any one
fetch()
fails. - (2) will perform all the
imageObj.value ...
andelement.src = ...
stuff for all successful fetches even if one or morefetch()...
fails. Any single failure will causePromise.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.
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);
});