【问题标题】:waiting for ajax to complete before next ajax call在下一次 ajax 调用之前等待 ajax 完成
【发布时间】:2014-07-06 02:18:26
【问题描述】:

我正在尝试等待 ajax 调用完成模型的保存,然后再保存列表中的下一个模型。我在谷歌上搜索,看到了一些关于延迟对象的东西,这些东西对我来说是新的,另一个有递归函数的答案就是这样做的。我尝试了递归方法,因为它似乎比使用延迟对象和使用$.when.apply($, arrayOfAjaxCalls).then() 更有意义。所以那个代码(递归的,看起来像:

    saveModel(index, numRequests) {
        var self = this;

        if (index < numRequests) {
            var sample = self.samplesToSave[index];    

            return $.ajax({
                url: model.url,
                contentType: "application/json",
                type: "POST",
                data: JSON.stringify(model),
                crossDomain: $.support.cors,
                xhrFields: {
                    withCredentials: $.support.cors,
                },
                success: function(data) {
                    console.log("JUST SAVED");
                    console.log(data);
                },
                error: function(xhr: any) {
                    console.log(xhr);
                },
            }).then(() => {
                self.saveModel(index + 1, numRequests);
            });
        }
    }

我这样称呼它:

saveModel(0, _.size(myCollection)

在调用下一个 saveModel 之前,它实际上并没有等待 ajax 调用以其当前状态完成。它基本上只是按顺序为集合中的每个项目同步调用 saveModel 。对我所缺少的有什么想法吗?如果 $.Deferred 有更好的解决方案,我也可以。谢谢。

编辑:对不起,它的意思是在 saveModel 函数的最后一行说 saveModel。试图摆脱特定领域的部分。而且我使用的是打字稿,而不是咖啡稿

新尝试:

    saveSampleNew() {
        var d = $.Deferred();
        d.resolve();
        var p = d.promise();
        var self = this;
        self.samplesToSave.forEach(sample => p = p.then(() => self.makeSaveRequest(sample)));

        return p;
    }

     makeSaveRequest(sample) {
        var self = this;

        return $.ajax({
            url:  "samples",
            contentType: "application/json",
            type: "POST",
            data: JSON.stringify(sample),
            crossDomain: $.support.cors,
            xhrFields: {
                withCredentials: $.support.cors,
            },
            success: function(data) {
                console.log("SAVED12");
                console.log(data);                    
            },
        });
    }

由于此代码依赖于其他异步调用的完成,我将这个新尝试称为:

this.saveContainers(project).then(() => {

}).done(() => {
    self.saveSampleNew();
});

【问题讨论】:

  • coffescript 吗?如果是,请用它标记您的问题。
  • 在哪里你把“下一个 saveModel”叫做?我唯一能看到的是self.modelDeferred(…)。请提供一个完整的例子。
  • @Bergi:看起来更像 ES6 代码。
  • 代码看起来应该可以按预期工作。如果您不熟悉承诺/延迟对象,请查看 learn.jquery.com/code-organization/deferredshtml5rocks.com/en/tutorials/es6/promises
  • @FelixKling:这就是我问的原因。 Afaik,来自带有块体的 ES6 箭头函数,您需要明确地return。当然,不管是什么语言,在箭头函数中使用self 代替this 没有多大意义。

标签: javascript jquery ajax recursion promise


【解决方案1】:

不,它应该这样工作。如果您认为它不会等待,请提供更多信息,说明您如何调用它以及它同步递归的体验。

但是递归调用有一个问题:

.then(function() {
  self.saveModel(index + 1, numRequests);
})

then 返回的承诺,以及随后由您的saveModel 方法返回的承诺,会直接通过第一个ajax 调用解决,它不会等待递归链。其他 ajax 调用仍在发生(按预​​期顺序依次),但没有被生成的 Promise 跟踪。

要获得它,并正确地链接承诺,以便它使用最后一个(“最里面”)承诺的结果来解决,你需要 return 从回调到 @ 987654325@:

.then(function() {
  return self.saveModel(index + 1, numRequests);
})

【讨论】:

  • 我试过了,它似乎不起作用。它像以前一样按顺序调用 saveModel,但实际上并没有在第二次调用之前等待 saveModel() 第一次完成。
【解决方案2】:

我可能会在这里使用 for 循环而不是递归调用,通常 - 我发现在这种情况下更容易阅读。

saveModel() {
     var d = $.Deferred(); d.resolve();
     var p = d.promise(); // to start the chain
     this.samplesToSave.forEach(sample => p = p.then(() => makeSaveRequest(sample));
     return p;
}

makeSaveRequest(sample) {
    return $.ajax({...}); // make request using `sample` as data
} 

【讨论】:

  • 这个我试过了,但是好像没有达到等待第一个makeSaveRequest完成后再为下一个对象再次调用它的效果。
  • @Crystal 那么你可能用错了,你能给我举个例子吗?你确定 makeSaveRequest 是 return $.ajax(... 吗?
  • 好的,我在底部附近更新了我的原始帖子。你能看看吗?谢谢。
  • 好的,我添加了我如何称呼它。让我知道您是否还需要所有其他方法。我认为这是更多的领域逻辑,可以省略。
  • @Crystal 你没有在任何地方等待它,你是如何完成它的?你需要做this.saveContainers(project).then(() =&gt; self.saveSampleNew()).done(function(p){ console.log("Done saving all values!"); });
猜你喜欢
  • 2012-10-13
  • 1970-01-01
  • 2017-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-19
相关资源
最近更新 更多