jQuery 延期/承诺
jQuery Deferred / Promise
我试图在循环中使用 deferred/promise,但出现了奇怪的行为。我的代码如下:
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));
});
});
代码中使用的 Blob 是我从远程网络服务获取的对象数组,其中包含有关图像的属性(准确地说,它来自 filepicker.io 的 pickandstore 方法)。
当我 运行 这样做时,我在控制台中得到以下信息:
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":""
}
]
虽然正确显示images[0]和images[1],但是当单独打印时,对象数组只显示两次images[1]!!!
我是不是做错了什么???
提前感谢您的宝贵时间。
更新: 我根据@TrueBlueAussie
的评论更正了代码
您在每次 doAsyncOriginal()
调用中重复使用同一个 image
对象,因此 images
数组的每个元素都指向同一个对象。
您需要在函数内部创建对象:
var image = {}; // <-- delete this
function doAsyncOriginal(i) {
var image = {};
// ...
}
此问题与 promises/deferreds 无关,并且 promises/deferreds 在您的代码中确实没有任何作用。你可以这样做:
$(function(){
var images = Blobs.map(function (blob) {
return {
original: blob.key,
resized: '',
thumbnail: ''
};
});
console.log(JSON.stringify(images));
});
在 doAsyncOriginal
中,您在返回它的 promise 之前解决您的 deferred,甚至在它上面添加 done 处理程序之前。
您应该延迟 defer.resolve(i)
调用,因此延迟将在稍后解决并进入完成处理程序...
function doAsyncOriginal(i) {
var defer = $.Deferred();
// ...
// Function.bind equivalent to jQuery.proxy
window.setTimeOut(defer.resolve.bind(defer, i), 0);
return defer.promise();
}
我试图在循环中使用 deferred/promise,但出现了奇怪的行为。我的代码如下:
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));
});
});
代码中使用的 Blob 是我从远程网络服务获取的对象数组,其中包含有关图像的属性(准确地说,它来自 filepicker.io 的 pickandstore 方法)。
当我 运行 这样做时,我在控制台中得到以下信息:
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":""
}
]
虽然正确显示images[0]和images[1],但是当单独打印时,对象数组只显示两次images[1]!!!
我是不是做错了什么???
提前感谢您的宝贵时间。
更新: 我根据@TrueBlueAussie
的评论更正了代码您在每次 doAsyncOriginal()
调用中重复使用同一个 image
对象,因此 images
数组的每个元素都指向同一个对象。
您需要在函数内部创建对象:
var image = {}; // <-- delete this
function doAsyncOriginal(i) {
var image = {};
// ...
}
此问题与 promises/deferreds 无关,并且 promises/deferreds 在您的代码中确实没有任何作用。你可以这样做:
$(function(){
var images = Blobs.map(function (blob) {
return {
original: blob.key,
resized: '',
thumbnail: ''
};
});
console.log(JSON.stringify(images));
});
在 doAsyncOriginal
中,您在返回它的 promise 之前解决您的 deferred,甚至在它上面添加 done 处理程序之前。
您应该延迟 defer.resolve(i)
调用,因此延迟将在稍后解决并进入完成处理程序...
function doAsyncOriginal(i) {
var defer = $.Deferred();
// ...
// Function.bind equivalent to jQuery.proxy
window.setTimeOut(defer.resolve.bind(defer, i), 0);
return defer.promise();
}