异步后处理回复

时间:2016-12-08 04:38:42

标签: javascript knockout.js

我正在尝试上传图片列表。我将图像存储在一个数组中(称为图像)。

我在屏幕上显示预览。

我想要做的是按顺序上传它们,当它们完成上传时,我想设置一个标志。设置此标志时(由于Knockout的强大功能),图像将从列表中消失。

但是,我认为由于post命令的异步特性......我没有达到预期的效果。

以下是我要做的事情:

for(var i = 0; i < self.images().length; i++) {
  var photo = self.images()[i];
  var thisItem = photo;
  var object = JSON.stringify({
    Image: thisItem.Image,
    AlbumID: albumId,
    Filesize: thisItem.Filesize,
    Filetype: thisItem.Filetype,
    Description: thisItem.Description,
    UniqueID: thisItem.UniqueID
  });
  var uri = "/api/Photo/Upload";
  $.post({
    url: uri,
    contentType: "application/json"
  }, object).done(function(data) {
    if(data.IsSuccess) {
      photo.Status(1);
    }
  }).fail(function() {
    // Handle here
  }).always(function() {
    remainingImages = remainingImages - 1;
    if(remainingImages == 0) self.isUploading(false);
  });
}
self.isUploading(false);

但我认为正在发生的事情是for循环在所有帖子收到回复之前结束。因为在线删除了一张图片。

我尝试使用async: false ajax帖子,但这会锁定屏幕然后它们都消失了。

我认为“完成”方法只会在帖子完成后执行,但我认为整个方法只在发送了post命令后才结束,然后我就永远不会得到done

我如何实现我想要做的...在帖子得到答复后设置每个图像的状态?

1 个答案:

答案 0 :(得分:3)

你的第一个问题是你丢失了你认为对每个photo对象的引用,因为循环在你的AJAX调用返回之前完成,所以当它们返回时,photo是一个引用到self.images()中的最后一项。

我们需要做的就是为循环的每次迭代创建一个 new 范围,每个范围都有自己对特定photo的引用。 JavaScript具有函数范围,因此我们可以通过将每个photo传递给函数来实现我们的目标。我将使用Immediately Invoked Function Expression (IIFE)作为示例:

for (var i = 0; i < self.images().length; i++) {
    var photo = self.images()[i];
    (function (thisItem) {
        /* Everything else from within your for loop goes here. */
        /* Note: the done handler must reference `thisItem`, not `photo`. */
    })(photo);
}

请注意,您应该从最后一行删除self.isUploading(false);。在所有POST请求都返回之前,不应将其设置为false。

我创建了一个功能齐全的小提琴,你可以看到here

但是,此解决方案不会按顺序执行POST请求&#34;。我不确定你为什么要在发送下一个POST之前等待一个POST返回,因为这只会增加用户必须等待的时间。但为了完整起见,我将解释如何做到这一点。

要在上一次POST返回后触发POST,您需要删除for循环。您将需要一种方法来调用上一个POST的always处理程序中的下一个POST。这是recursive函数的一个很好的候选者。

在我的解决方案中,我使用index来跟踪images上次发布的项目。我递归调用函数对images中的下一个项目执行POST,直到我们在images中发布了所有项目。以下代码替换for循环:

(function postNextImage (index) {
    var photo = self.images()[i];
    var thisItem = photo;
    var object = JSON.stringify({
        Image: thisItem.Image,
        AlbumID: albumId,
        Filesize: thisItem.Filesize,
        Filetype: thisItem.Filetype,
        Description: thisItem.Description,
        UniqueID: thisItem.UniqueID
    });

    var uri = "/api/Photo/Upload";

    $.post({
        url: uri,
        contentType: "application/json"
    }, object)
    .done(function (data) {
        if(data.IsSuccess) {
            thisItem.Status(1);
        }
    })
    .fail(function () {
        // Handle here
    })
    .always(function () {
        if (index < (self.images().length - 1)) {
            index += 1;
            postNextImage(index);
        } else {
            self.isUploading(false);
        }
    });

})(0);

我也创建了这个解决方案的小提琴,可以找到here