我的jquery $ .Deferred没有阻止另一个$ .ajax调用发生直到解决

时间:2014-06-10 23:13:05

标签: javascript jquery ajax promise jquery-deferred

我正在使用长轮询来检索带有图片网址的大型json Feed。我是在success请求的$.ajax部分中预加载这些网址,并希望在完全加载后调用函数对这些图像执行某些操作。我尝试使用$.Deferred请求的complete部分中的$.ajax对象,并在图像预加载循环结束时解析$.Deferred来实现此目的。< / p>

但是,当我监视控制台时,我可以看到在图像预加载时继续进行$.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)
}

1 个答案:

答案 0 :(得分:3)

$.when等待 promises

您正在传递一个延迟对象。它反过来通过包装它转换为一个承诺,所以等待它立即产生它作为值。所以.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
}

看看它是多么清晰和热它只有两个级别的缩进,这是因为promises链。如果您的代码是连续的,那么大致如下:

  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这样更强大的库。