【问题标题】:When to resolve promises in ajax calls何时解决 ajax 调用中的承诺
【发布时间】:2014-05-10 01:25:26
【问题描述】:

我刚开始对多个 ajax 调用使用 Promise,我不知道我需要创建多少。我找到了这些帖子:

jQuery Deferred - waiting for multiple AJAX requests to finish jQuery make dynamic ajax calls and wait for them to complete

所以我尝试使用 Promise,在这个简单的例子中:

function doSomething1() {
  var deferred1 = $.Deferred();
  setTimeout(function() {
    deferred1.resolve();
  }, 2000);
  return deferred1.promise();
}

function doSomething2() {
  var deferred2 = $.Deferred();
  setTimeout(function () {
    deferred2.resolve();
  }, 1000);
  return deferred2.promise();
}

var promise = doSomething1();
var promise2 = doSomething2();

function multiplePromises() {
  var promises = [];
  for (var i = 0; i < 3; i++) {
      var deferred = $.Deferred();
      deferred.resolve();
      promises.push(deferred);
  }
  return $.when.apply(undefined, promises).promise();
}


multiplePromises().done(function () {
  console.log("yay");
});

我马上就明白了。现在模拟一个ajax调用,我尝试使用setTimeout。像这样:

function multiplePromises2() {
  var promises = [];
  for (var i = 0; i < 3; i++) {
      setTimeout(function () {
      var deferred = $.Deferred();
      deferred.resolve();  
      promises.push(deferred);
      },2000);      
  }
  return $.when.apply(undefined, promises).promise();
}

multiplePromises2().done(function () {console.log("timeout and promises");});

我没有得到实际的两秒延迟。如果我试试这个:

function multiplePromises2() {
  var promises = [];
  for (var i = 0; i < 3; i++) {
      var deferred = $.Deferred();
      setTimeout(function () {
      deferred.resolve();  
      },2000);
      promises.push(deferred);
  }
  return $.when.apply(undefined, promises).promise();
}

我从来没有收到过 multiplePromises2 已经完成的消息。所以在我实际的 ajax 调用中,我无法使用 deferred。我试过这样做:

    saveNewProjects(projects) {
        var projectPromises: any[] = [];

        for (var projectName in projects) {
            var project = projects[projectName][0].Project;
            if (project && project.id == 0 && project.name !== null) {
                var deferred = $.Deferred();

                var postProject = $.ajax({
                    url: "projects",
                    contentType: "application/json",
                    type: "POST",
                    data: JSON.stringify(project),
                    crossDomain: $.support.cors,
                    xhrFields: {
                        withCredentials: $.support.cors,
                    },
                    success: function (data) {
                        deferred.resolve(data);
                    },

                });
                projectPromises.push(postProject);
            }
        }
        return $.when.apply($, projectPromises).promise();
    }

我这样称呼那个函数:

 this.saveNewProjects(projects).then(() => {

我是否在考虑承诺并适当地推迟?它似乎没有到达我的 then 或 done 回调。提前致谢。

【问题讨论】:

  • 您需要仔细考虑代码的哪些部分是同步的,哪些不是(即在超时后将项目添加到承诺列表中演示异步调用,您希望同步将项目添加到列表和异步 @987654329 @...)。

标签: javascript jquery ajax


【解决方案1】:

这是一个令人讨厌的小问题,但问题不是因为您错误地使用了 deferred,而是因为您的想法正确:而是因为您遇到了闭包问题。

我们来看这个例子:

function multiplePromises2() {
    var promises = [];
    for (var i = 0; i < 3; i++) {
        var deferred = $.Deferred();
        setTimeout(function () {
            deferred.resolve();  
        },2000);
        promises.push(deferred);
    }
    return $.when.apply(undefined, promises).promise();
}

这似乎很无辜。但不幸的是,您实际上并没有为循环的每次迭代定义一个新变量deferred。 javascript 解释器将所有变量声明移动到作用域的顶部。所以这实际上等同于:

function multiplePromises2() {
    var promises, deferred;
    promises = [];
    for (var i = 0; i < 3; i++) {
        deferred = $.Deferred();
        setTimeout(function () {
            deferred.resolve();  
        },2000);
        promises.push(deferred);
    }
    return $.when.apply(undefined, promises).promise();
}

您知道为什么现在可能会出现问题吗?在 setTimeout 中对变量 deferred 的引用实际上发生了变化,因为您在每次迭代时都在更新 deferred。因此,当 2 秒结束时,您正在解决一个延迟(在 promises[2] 处)三次。为了证明这一点,您可以在 setTimeout 中添加以下行:console.log(promises.indexOf(deferred));

既然我们已经确定了问题,那么解决起来就很容易了。只是一个标准的 IIFE 解决方案:

function multiplePromises2() {
    var promises, deferred;
    promises = [];
    for (var i = 0; i < 3; i++) {
        deferred = $.Deferred();
        (function(deferred) {
            setTimeout(function () {
                deferred.resolve();  
            },2000);
            promises.push(deferred);
        })(deferred);
    }
    return $.when.apply(undefined, promises).promise();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-19
    • 1970-01-01
    • 1970-01-01
    • 2017-12-14
    • 1970-01-01
    • 2013-06-22
    • 2018-03-18
    • 2023-03-28
    相关资源
    最近更新 更多