这对AJAX请求是竞争条件吗?

时间:2011-12-06 23:09:07

标签: javascript jquery ajax race-condition

我正在创建一个以新闻文章为特色的网站。这些文章将显示在页面底部的两列中。底部会有一个按钮来加载其他新闻报道。这意味着我需要能够指定要加载的新闻故事。服务器端,我只是在我的SQL语句中使用LIMIT子句实现它,提供:first参数,如下所示:

SELECT * 
FROM news 
ORDER BY `date` DESC 
LIMIT :first, 1

这意味着,在客户端,我需要跟踪我加载了多少新闻。我已经通过将加载新信息的函数保存在一个具有包含加载项数的属性的对象中来实现这一点。我担心这在某种程度上是一种我没有看到的竞争条件,但是,在数字递增之前我的loadNewInformation()将被调用两次。我的代码如下:

var News = {

    newInfoItems: 0,

    loadNewInformation: function(side) {
        this.newInfoItems += 1;
        jQuery.get(
            '/api/news/'+ (this.newInfoItems - 1),
            function(html) {
                jQuery('div.col'+side).append(html);
            }
        );
    }
}

在页面加载时,将以下列方式调用它:

News.loadNewInformation('left');
News.loadNewInformation('right');

我本可以通过这样的方式实现这一点:第一次调用的成功处理程序为第二次调用创建了另一个AJAX请求,这显然不是竞争条件......但这看起来像是邋code的代码。想法?

5 个答案:

答案 0 :(得分:1)

是的,从技术上讲,这可能会造成各种竞争条件。这些调用是异步的,如果由于某种原因第一次被阻止,第二次调用可能会先返回。

但是,由于你的回调功能不是很重要,而这些功能取决于其他方面的存在。人口稠密,我不知道它应该给你带来多大的悲伤。

答案 1 :(得分:1)

(是的,有竞争条件。)

仅解决JavaScript

页面上的所有JavaScript代码(不包括Web-Workers)(包括回调)都是“互斥”运行。

在这种情况下,因为newInfoItems是急切评估的,所以它甚至不复杂:保证“/ api / news / 0”和“/ api / news / 1”都被取出(或尝试失败)。将其与此相比:

// eager evaluation: value of url computed BEFORE request
// this is same as in example (with "fixed" increment order ;-)
// and is just to show point
var url = "/api/news/" + this.newInfoItems
this.newInfoItems += 1;
jQuery.get(url, 
    function(html) {
        // only evaluated on AJAX callback - order of callbacks
        // not defined, but will still be mutually exclusive.
        jQuery('div.col'+side).append(html);
    }
);

但是,AJAX请求完成的 order 未定义,并受服务器和浏览器的影响。此外,如下所述,在服务器和各个AJAX请求之间没有建立原子上下文

解决上下文中的JavaScript

现在,即使已经确定将调用“/ api / news / 0”“/ api / news / 1”,想象一下不太可能,但理论上可能情况:

  • 文章B,A存在于数据库
  • 浏览器同时发送两个AJAX请求 - 异步,这没关系!
  • 某个时间之间将文章添加到数据库中
    • 服务器处理news/0请求和
    • 服务器处理news/1请求

然后,发生了这种情况:

  • news/0返回文章B(数据库中的文章B,A
  • 文章C已添加
  • news/1返回文章B(数据库中的文章C,B,A

请注意,文章B已返回两次!糟糕:)

所以,虽然竞争条件“似乎不太可能”,但确实存在。如果在news/1之前处理news/0并且(再次)在请求之间添加文章,则会出现类似的竞争条件(具有不同的结果):没有在任何一种情况下原子保证

(如果增加新文章的时间增加,如果串联执行AJAX请求,则上述竞争条件

可能的解决方案

考虑在单个请求中提取say n(2个没问题!)文章(例如“/ api / latest / n”),然后根据需要列出文章回调中的 。例如,左边的文章的前半部分和右边的后半部分,或者任何合适的文章。

除了通过使单个请求成为原子操作(相对于文章添加)消除上述特定竞争条件,它还将减少网络流量并减少服务器的工作量。

API的获取可能如下所示:

SELECT * 
FROM news 
ORDER BY `date` DESC 
LIMIT :n

快乐的编码。

答案 2 :(得分:0)

不应该是任何竞争条件,代码中必须有其他错误。计数器在.get()调用之前递增,因此在每次调用之前,计数器应正确递增。举个简单的例子说明它在按顺序调用时有效:http://jsfiddle.net/KkpwF/

答案 3 :(得分:0)

我估计你在暗示newItemInfo柜台?

观察:

  1. 您正在调用News.loadNewInformation两次,其回调函数将在AJAX完成时执行。
  2. 您提供的回调方法不会改变News对象。
  3. 在这种情况下,您不必担心。对News.loadNewInformation的第二次调用只会在第一次调用完成后执行 - 也就是说,不包括执行回调方法。因此,您的newItemInfo计数器将包含正确的值。

答案 4 :(得分:0)

试试这个:

loadNewInformation: function(side) {
    jQuery.get(
        '/api/news/'+ (this.newInfoItems++),
        function(html) {
            jQuery('div.col'+side).append(html);
        }
    );
}