【问题标题】:jQuery Deferred / PromisejQuery 延迟/承诺
【发布时间】:2015-03-27 08:02:53
【问题描述】:

我试图在循环中使用 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 是我从远程 Web 服务获取的对象数组,其中包含有关图像的属性(准确地说,它来自 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],但是分开打印时,object数组只显示两次images[1]!!!

我是不是做错了什么???

提前感谢您的宝贵时间。

更新:我根据@TrueBlueAussie 的评论更正了代码

【问题讨论】:

  • 旁注:您正在将代码包装在 doAsyncOriginal 内的 DOM 就绪处理程序中。这不是必需的,因为调用代码已经包含在一个中。这也意味着您正在立即解决承诺。
  • 问:假设在什么时候加载图像?
  • @TrueBlueAussie 感谢您的评论,我删除了它们,但仍然可以正常工作。运行此代码时已加载图像,Blob 对象从回调函数返回。我的问题与循环有关。当数组的所有元素都被推送时,我想将数组传递给另一个函数。

标签: javascript jquery arrays promise deferred


【解决方案1】:

您在每次调用 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));
});

【讨论】:

    【解决方案2】:

    doAsyncOriginal 中,您在返回它的承诺之前或什至在添加完成处理程序之前解决您的延迟。

    你应该延迟defer.resolve(i)调用,所以延迟的会在稍后解决并进入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();
    }
    

    【讨论】:

    • promise 上的 .done() 处理程序是内置的。不必手动添加。你在这里做什么是没有意义的。
    • @JLRishe 我的意思是定义回调函数,谢谢指正。
    • 回调函数在解决之前不必添加到承诺中。 OP 代码中的承诺工作正常。该问题与承诺无关。
    • @JLRishe 所以在 resolved 承诺中,如果我定义了一个 done 回调,那么无论如何都会调用回调?这个调用是如何管理的(在堆栈中,延迟)?
    • 是的,没错。在符合 Promises/A+ 的承诺中,必须推迟对处理程序的调用 (promisesaplus.com/#point-34),但看起来已经解决的 jQuery 承诺会立即调用它们的处理程序:jsfiddle.net/acn4r4vs
    猜你喜欢
    • 2023-03-21
    • 1970-01-01
    • 2015-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-10
    • 2019-04-26
    相关资源
    最近更新 更多