【问题标题】:My jquery $.Deferred is not preventing another $.ajax call from happening until resolved我的 jquery $.Deferred 在解决之前不会阻止另一个 $.ajax 调用发生
【发布时间】:2014-07-31 21:15:01
【问题描述】:

我正在使用长轮询来检索带有图像 URL 的大型 json 提要。我正在我的$.ajax 请求的success 部分中预加载这些网址,并且希望在这些图像完全加载后调用一个函数来处理这些图像。我试图通过在我的$.ajax 请求的complete 部分中使用$.Deferred 对象并在我的图像预加载循环结束时解析$.Deferred 来做到这一点。

但是,当我监控控制台时,我可以看到在预加载图像时继续进行 $.ajax 调用。 $.Deferred 直到预加载循环结束才解决,所以我不明白为什么会发生这种情况。我对$.Deferred 的了解有限,但我正在努力了解更多信息,因此有关为什么会发生这种情况以及如何解决此问题的任何建议都会很棒。我得到的理解是,它们是一种防止函数在被保留之前被调用的方法......

作为奖励,除了丑陋的代码之外,是否存在发出多个$.ajax 请求并对返回的数据执行相同操作的问题?谢谢

$(function(){
    (function poll(){
        var streamUrl = 'http://demofeed';
        var def = $.Deferred();
        console.log('about to get');
        setTimeout(function(){
            $.ajax({
                url: streamUrl,
                dataType: 'json',
                success: function(data) {
                    createArray(data, def);
                },
                complete: function () {
                    $.when(def).done(function() {
                        //Long-poll again
                        poll();
                    });
                },
                error: function(){
                    setTimeout(function(){
                        console.log('There was an error with the XHR Request');
                        poll();
                    }, 3000);
                }
            });
        }, 7000);
    })();
});


function createArray(data, defer){
    console.log('creating array');
    var entries = data['entries'];
    for (var k = 0, j = entries.length; k < j; k++) {
        console.log('there is new media');
        if (entries[k].img) {
            var img = new Image();
            img.onload = (function(entry) {
                return function() {
                    validArray.push(entry);
                    console.log('New Media Loaded');
                }
            })(entries[k]);
            img.onerror = function(){
                console.log('error: bad image source');
            };
            img.src = entries[k].url;
        } else {
            console.log('Not an image');
        }
    }
    defer.resolve(); //Here is where I resolve the deferred object, once for loop is done (all images have been loaded)
}

【问题讨论】:

  • 您的问题有什么更新吗?
  • 是的。您的回答修复了它,并感谢您推荐 jQuery 的替代品。我想如果没有任何库也不会太难做到这一点......同意吗?

标签: javascript jquery ajax promise jquery-deferred


【解决方案1】:

$.when 等待承诺

您正在向它传递一个延迟对象。它反过来通过包装它被转换为一个promise,因此等待它立即以它作为值产生。所以.when 立即执行。您可以改为使用def.promise() 来获得承诺。

也就是说,如果我是你,我可能会在整体上做一个更有前途的 API。

var delay = function(ms){
   var def = $.Deferred();
   setTimeout(function(){ def.resolve(); },ms);
   return def.promise();
}

这会让我做什么:

function poll(){
    console.log('about to get');
    return delay(7000).then(function(){
        return $.get('http://demofeed');
    }).then(function(){ // success case
         return createArray(data); // we'll get to it later
    }), function(){ // handle error
          console.log('There was an error with the XHR Request');
          return delay(3000); // wait 3 ms
    }).then(poll); // long poll
}

看它有多清晰,有多热它只有两级缩进,这是因为承诺链。如果您的代码是连续的,大致是这样的:

  function poll(){
      sleep(7000);
      try{
          var data = $.get('http://demofeed'); // assume this is sync
          arr = createArray(data);
      } catch(e) {
          console.log("There was an error with the XHR Request");
          sleep(3000); 
      }
      poll(); /// call again
  }

至于加载图片功能,可以考虑在其上使用$.when.apply$.when等待多个值:

function createImages(data){ // what does this return?
    var promises = data.entries.map(function(entry){
        var img = new Image();
        var d = $.Deferred();
        img.onload = function(entry){ d.resolve(entry); };
        img.onerror = function(){ console.log("Bad Image usage"); }
        return d.promise();
    });
    // this will actually _wait_ for the images now.
    return $.when.apply($, promises); 
}

最后一点,如果我是你,我会避免使用 jQuery 承诺并使用像 Bluebird 这样功能更强大的库。

【讨论】:

  • 这段代码看起来很棒。你说“如果你的代码是连续的……”那代码($.ajax 请求)不是总是连续的吗?另外,我对 promises 的想法很陌生,你会推荐 jQuery 或 Bluebird 来学习吗?
  • Afaik $.when 确实接受带有 .promise 方法的任何东西作为承诺,包括延迟?他的问题只是他在createImages函数中同步调用了defer.resolve();
  • @Startec jQuery 是一个糟糕的实现。我肯定会推荐 Bluebird。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-14
  • 2011-03-19
  • 2020-10-16
  • 2018-08-20
  • 1970-01-01
  • 2017-12-14
相关资源
最近更新 更多