Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jquery/83.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 这对AJAX请求是竞争条件吗?_Javascript_Jquery_Ajax_Race Condition - Fatal编程技术网

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

Javascript 这对AJAX请求是竞争条件吗?,javascript,jquery,ajax,race-condition,Javascript,Jquery,Ajax,Race Condition,我正在创建一个以新闻文章为特色的网站。这些文章将出现在页面底部的两列中。底部将有一个按钮,用于加载其他新闻故事。这意味着我需要能够指定要加载的新闻故事。在服务器端,我只是在SQL语句中使用一个LIMIT子句来实现它,并提供:first参数,如下所示: SELECT * FROM news ORDER BY `date` DESC LIMIT :first, 1 这意味着,在客户端,我需要跟踪我加载了多少条新闻。我通过将加载新信息的函数保存在一个对象中实现了这一点,该对象的属性包含加载的项

我正在创建一个以新闻文章为特色的网站。这些文章将出现在页面底部的两列中。底部将有一个按钮,用于加载其他新闻故事。这意味着我需要能够指定要加载的新闻故事。在服务器端,我只是在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请求,这显然不是竞争条件……但这看起来像是草率的代码。想法?

是的,从技术上讲,这可能会造成某种比赛条件。这些调用是异步的,如果第一个调用由于某种原因被阻塞,第二个调用可能会首先返回

但是,由于您的回调函数中没有太多依赖于正在填充的另一方的存在的内容,我不认为这会给您带来太多的痛苦。

(是的,存在竞争条件。)

只处理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请求完成的顺序没有定义,并且受服务器和浏览器的影响。此外,正如下面所讨论的,在服务器和单个AJAX请求之间没有建立原子上下文

在上下文中寻址JavaScript 现在,即使已经确定将调用“/api/news/0”和“/api/news/1”,想象一下这种不太可能但理论上可能出现的情况:

  • 数据库中存在文章
    B,A
  • 浏览器同时发送两个AJAX请求——异步或同步,这无关紧要
  • 在以下时间之间的某个时间向数据库添加一篇文章:
    • 服务器处理
      新闻/0
      请求,并
    • 服务器处理
      news/1
      请求
然后,这种情况发生了:

  • news/0
    返回文章
    B
    (数据库中的文章
    B,A
  • 添加了第条
    C
  • news/1
    返回文章
    B
    (数据库中的文章
    C、B、A
请注意,文章
B
返回了两次!哎呀:)

因此,尽管竞争条件“似乎不太可能”,但它确实存在。如果在
news/0
之前处理了
news/1
,并且(再次)在请求之间添加了一篇文章,则可能会出现类似的竞争条件(结果不同):在这两种情况下都没有原子保证

(如果随着添加新文章的时间的增加,连续执行AJAX请求,则更可能出现上述竞争情况。)

可能的解决办法 考虑在单个请求中获取(比如,
n
(2个就可以了!)文章(例如“/api/latest/n”),然后在回调中适当地布局这些文章。例如,文章的前半部分在左边,后半部分在右边,或者任何合适的地方

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

然后,API的提取可能如下所示:

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

快乐编码。

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

我想你是在
newItemInfo
计数器上暗示的

意见:

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

    尝试以下操作:

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

    有没有更优雅的方式来处理这件事?@Ryan-你能详细说明一下“优雅”吗?你的意思是“有没有一种方法可以确保它们总是按照我调用它们的顺序填充”?您已经暗示,您看到了如何通过在第一个函数的回调函数中调用第二个load来实现这一点。理想的情况是,你不想把它们纠缠在一起。您可以创建一个挂起请求队列,启动一个,然后绑定到
    ajaxStop
    ,等待第一个请求返回,然后再启动第二个请求。我想,更“优雅”的意思是,如果高级开发人员看到,他们不会嘲笑我的东西如果一个页面出现在另一个页面之前,我并不担心,因为页面看起来仍然很好。它们被塞进绝对定位的div中,因此它们的布局不受其他div的影响。我用完全未经测试的代码创建了一个div,它可能会做一些更像您想要的事情。让我