2

JavaScript 是否保证是单线程的? 很明显,尽管 javascript 是单线程的,但仍有一些警告。

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

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

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

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

4

2 回答 2

1

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


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

如果检测到不再需要运行,您能否检查您的成功函数 + 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);

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

于 2012-04-20T16:25:12.493 回答
1

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

来自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; 
     });
});

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

于 2012-04-20T16:30:18.750 回答