如何在超时后使用jQuery Deferred / Promise和第二个$ .ajax()

时间:2016-04-15 11:23:19

标签: jquery promise jquery-deferred deferred

我有一个绑定到$someEl的事件处理程序,它只应在oRes填充数据时执行,数据可以来自主要来源(getData1())或备份来源( getData2())。仅当主要源超时时才从备份源请求数据。

如果主要来源没有超时,那么一切正常;但是,当调用备份getData2()函数时,dfd永远不会被解析,因此当我点击$someEl时没有任何记录。我怀疑它无法正常工作,因为getData2()中的Deferred对象正在覆盖dfd点击处理程序所指的$someEl变量。

我有一种感觉,我没有使用"最佳实践"来应用延期/承诺。图案。鉴于这种情况,如何使点击处理程序正确等待oRes在超时后从主AJAX响应或辅助AJAX响应中填充?

一些澄清说明:

  • getData1()必须在文档准备好后执行
  • $someEl.click()可能会在文档加载过程中随时触发,因此需要在$(document).ready()
  • 之外定义事件处理程序
  • 我坚持使用jQuery 1.7.1

以下是代码:

var oRes, dfd;

// Get data from primary source
function getData1() {
  dfd = $.ajax({
    ...
    success: function(data) {
      oRes = data;
    },
    error: function(jqXHR, textStatus, errorThrown) {
      if (textStatus==='timeout') getData2();
    },
    timeout: 10000 // 10-second timeout
  });
}

// Get data from backup source
function getData2() {
  dfd = $.ajax({...});
}

$someEl.click(function() {
  dfd.done(function() {
    console.log('This should only log when oRes is ready');
  });
});

$(document).ready(function() {
  getData1();
});

我在这支笔中模拟了我的情况:http://codepen.io/thdoan/pen/pyVyKj

基本上,我无法让事件处理程序输出"数据准备就绪!"填充oRes时,无需在加载页面后手动点击该框。

2 个答案:

答案 0 :(得分:0)

我会在ajax请求的回调中包含函数调用。

var oRes = null;
var dfd = null;

// Get data from backup source
function getData2() {
  dfd = $.ajax({...});
}

// Get the primary data source
function getData1() {
  dfd = $.ajax({
    success: function(data) {
        oRes = data;

        // set the click handler when oRes is successfully set
        $(someEl).click(function() {
            console.log('This should only log when oRes is ready');
        });
    },
    error: function(jqXHR, textStatus, errorThrown) {
      if (textStatus==='timeout') getData2();
    },
    always: function(){
        if (oRes==null){
            getData2();
        }
    }
    timeout: 10000 // 10-second timeout
  });
}

答案 1 :(得分:0)

我认为你只需要提升一个级别。

创建一个您的点击处理程序将侦听的延迟前台(并且该实例不会更改)。

然后,您可以解决从getData1()getData2()

延迟的延迟
var oRes,

    // Resolve this deferred when data has been successfully loaded:
    dfd = $.Deferred(),

     // But add listeners to this promise:
    dfdPromise = dfd.promise();

// Get data from primary source
function getData1() {
    $.ajax({
        ...
        success: function(data) {
            oRes = data;

            // Resolve when data loaded:
            dfd.resolve(data);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            if (textStatus==='timeout') getData2();
        },
        timeout: 10000 // 10-second timeout
    });
}

// Get data from backup source
function getData2() {
    $.ajax({...})
        .then(function(data){
            // Fallback data resolve:
            dfd.resolve(data);
        });
}

$someEl.click(function() {
    dfdPromise.done(function() {
        console.log('This should only log when oRes is ready');
    });
});

$(document).ready(function() {
    getData1();
});