Reputation: 3823
I'm trying to use deferred/promise in a loop, but I get strange behavior. My code is as follows:
var images = [];
var numImages = Blobs.length;
var image = {};
console.log("numImages: " + numImages);
function doAsyncOriginal(i) {
var defer = $.Deferred();
image.original = Blobs[i].key;
image.resized = '';
image.thumbnail = '';
images.push(image);
console.log("i: " + i + " image: " + image.original);
console.log("images[" + i + "]: " + images[i].original);
defer.resolve(i);
return defer.promise();
}
$(function(){
var currentImage = doAsyncOriginal(0);
for(var i = 1; i < numImages; i++){
currentImage = currentImage.pipe(function(j) {
return doAsyncOriginal(j+1);
});
}
$.when(currentImage).done(function() {
console.log(JSON.stringify(images));
});
});
The Blob used in the code is an array of objects that I get from remote webservice, which contains properties about the images (it comes from filepicker.io's pickandstore method to be precise).
When I run this, I get the following in console:
numImages: 2
i: 0 image: pictures_originals/3QnQVZd0RryCr8H2Q0Iq_picture1.jpg
images[0]: pictures_originals/3QnQVZd0RryCr8H2Q0Iq_picture1.jpg
i: 1 image: pictures_originals/MD3KO6GjT8SNFYoPcG8J_picture2.jpg
images[1]: pictures_originals/MD3KO6GjT8SNFYoPcG8J_picture2.jpg
[
{
"original":"pictures_originals/MD3KO6GjT8SNFYoPcG8J_picture2.jpg",
"resized":"",
"thumbnail":""
},
{
"original":"pictures_originals/MD3KO6GjT8SNFYoPcG8J_picture2.jpg",
"resized":"",
"thumbnail":""
}
]
Although it shows images[0] and images[1] correctly, when printing separately, the object array shows only twice images[1]!!!
Am I doing something wrong???
Thanks in advance for your time.
UPDATE: I corrected the code based on comment of @TrueBlueAussie
Upvotes: 0
Views: 185
Reputation: 443
In doAsyncOriginal
you resolve your deferred before returning it's promise or even before adding the done handler on it.
You should delay the defer.resolve(i)
call, so the deferred will be resolved later and enter the done handler...
function doAsyncOriginal(i) {
var defer = $.Deferred();
// ...
// Function.bind equivalent to jQuery.proxy
window.setTimeOut(defer.resolve.bind(defer, i), 0);
return defer.promise();
}
Upvotes: 0
Reputation: 101662
You are reusing the same image
object in every call to doAsyncOriginal()
, so every element of your images
array is pointing to the same object.
You need to create the object inside your function:
var image = {}; // <-- delete this
function doAsyncOriginal(i) {
var image = {};
// ...
}
This problem is unrelated to promises/deferreds, and promises/deferreds really aren't serving any purpose in your code. You could just do this:
$(function(){
var images = Blobs.map(function (blob) {
return {
original: blob.key,
resized: '',
thumbnail: ''
};
});
console.log(JSON.stringify(images));
});
Upvotes: 2