【问题标题】:Canceling an ajax request: can the handler still be executed取消ajax请求:handler还能被执行吗
【发布时间】:2012-04-20 16:02:59
【问题描述】:

Is JavaScript guaranteed to be single-threaded? 很明显,尽管 javascript 是单线程的,但仍有一些注意事项。

我想知道以下伪代码是否总是可预测的(我正在“使用”jQuery)

var lastReq;
$('#button').click(function()
{
  if (lastReq) lastReq.abort();
  lastReq = $.ajax(...);
});

这种情况可能是在单击事件和中止之间,来自服务器的数据通过并在事件队列中放置了一个事件。如果这发生在中止之前,将触发 ajax post 的 succes 事件。 我不知道如何真正测试这种可能的竞争条件。

有人知道这是如何工作的吗?或者如何用一个准备好的例子来测试这个?

【问题讨论】:

    标签: javascript jquery ajax jquery-deferred request-cancelling


    【解决方案1】:

    我不知道这种解决方法是否真的有用并且是防弹的(我正在尝试有创意)但是,由于 jQuery 1.5 ajax 方法返回一个延迟对象 lastReqstate() 方法可用

    来自http://api.jquery.com/deferred.state/

    deferred.state() 方法返回一个字符串,表示 Deferred 对象的当前状态。 Deferred 对象可以处于以下三种状态之一:

    ...

    "resolved":Deferred 对象处于已解决状态,这意味着该对象已调用 deferred.resolve() 或 deferred.resolveWith() 并且已调用 doneCallbacks (或正在被调用)。

    所以你可以像这样重构你的代码

    var lastReq;
    $('#button').click(function() {
         if (lastReq) {
             if (lastReq.state() === "resolved") {
                 return false; /* done() of the previous ajax call is in the process of
                                  being called. Do nothing and wait until the state 
                                  is resolved */
             }
             else {
                 lastReq.abort(); 
             }
         }
    
         lastReq = $.ajax(url).done(function() {
              /* do something */
              lastReq = null; 
         });
    });
    

    希望这可以帮助您提出一个想法,但我怀疑实际上不需要这种解决方法

    【讨论】:

      【解决方案2】:

      编辑: 一旦您中止请求,浏览器就不应再监听它了。所以当它到达事件队列中的响应时,我猜它应该把它扔掉。


      但是,如果您遇到问题,可以尝试以下方法:

      如果检测到不再需要运行,您能否检查您的成功函数 + url 以取消自身?

      例如(我并不是说你应该这样做,我没有尝试将任何东西附加到 jqXHR 请求):

      var numReq = 0, lastReq;
      
      $('#button').on('click', function(e) {
          if (lastReq) { lastReq.abort(); }
          numReq ++;
          lastReq = $.ajax({
              success : function(d, s, x) {
                  if (x.reqNum < numReq) { return; }
              }
          });
          lastReq.reqNum = numReq;
      });
      

      我的理解是 ajax 事件直到按钮点击完成后才会被添加到事件队列中,所以你不应该(理论上)担心在 ajax 之后设置 reqNum ...


      我也试过下面的代码:

      var numReq = 0, lastReq, timer = 100,
          c = setInterval(function() {
              if (lastReq) { lastReq.abort(); }
              numReq ++;
              lastReq = $.ajax({
                  url     : 'index.html',
                  cache   : false,
                  success : function(d, s, x) {
                      if (x.reqNum < numReq) { console.log('it happens'); }
                  }
              });
              lastReq.reqNum = numReq;
          }, timer);
      

      改变计时器以尝试匹配(尽可能接近)页面的加载时间。我还没有出现“它发生了”。

      【讨论】:

        猜你喜欢
        • 2022-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-08
        • 2011-04-23
        • 2011-01-28
        相关资源
        最近更新 更多