I am creating a function to lazy load images, when they are needed (using pagination to divide a large dataset into smaller chunks).
The problem is that the promise is nested in items[i].imagedata
.
The returned items
array contains still the Promise objects instead of the loaded images. This is probably because I used items.map()
, which created a copy of the array.
function getItemImages(items, paging, cb) {
var Promise = promise.Promise;
console.log("START",items,paging);
for (var i=paging.pageOffset; i<Math.min(paging.pageOffset+paging.pageLimit,items.length); i++) {
if (!items[i].hasOwnProperty("imagedata")) {
console.log("LOADING "+i+":",items[i]);
items[i].imagedata = mongodbService.getItemImage(items[i]._id);
}
}
Promise.all(items.map((item) => {
return Promise.all([item.imagedata]);
})).then((images) => {
console.log("RESULT",paging, items);
cb(paging, items);
});
}
You're right. The promise resolver isn't going to search for a promise inside another object. You need to return a promise for the whole thing you want to accomplish, although you can do that in pieces. Here, I added a separate function that returns a promise for items[i] with .imagedata mutated by chaining the getItemImage promise result. That promise in turn should be usable with all, so that Promise.all fires when all images are mutated.
Unless you're fulfilling a legacy interface somewhere that needs a callback parameter, it'd be better style to return Promise.all(promises) at the end so the caller could decide whether to be called back directly via its own callback or chain more operations onto the promise resolution and how to handle errors.
function getItemImages(items, paging, cb) {
var Promise = promise.Promise;
console.log("START",items,paging);
// Return a promise for items[i] with .imagedata
function promiseImage(i) {
return mongodbService.getItemImage(items[i]._id).
then(function(image) {
items[i].imagedata = image;
return items[i];
});
}
var promises = [];
for (var i=paging.pageOffset; i<Math.min(paging.pageOffset+paging.pageLimit,items.length); i++) {
if (!items[i].hasOwnProperty("imagedata")) {
console.log("LOADING "+i+":",items[i]);
// Add a new promise to promises
promises.push(promiseImage(i));
}
}
// promises is an array of promises, so "all" will work.
// Your code uses mutation, so the result isn't needed here.
// Previously, items was being sent to cb.
// cb might also consume the actual list of mutated items
// below.
Promise.all(promises).
then(() => {
console.log("RESULT",paging, items);
cb(paging, items);
});
}