这对AJAX请求是竞争条件吗?
Is this pair of AJAX requests a 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请求,这显然不会是一个竞争条件……但这看起来像是草率的代码。想法吗?
(是的,存在竞争条件)
只寻址JavaScript
一个页面上的所有JavaScript代码(不包括Web-Workers),包括回调,都是"互斥"运行的。
在这种情况下,因为newInfoItems是急切求值的,它甚至没有那么复杂:"/api/news/0"answers"/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请求——异步发送或同步发送,这无关紧要!
- 在
- 服务器处理
news/0
请求, - 服务器处理
news/1
请求
然后,发生以下情况:
-
news/0
返回文章B
(文章B,A
在数据库中) - article
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之前,计数器应该正确递增。一个简短的示例来演示顺序调用时的工作原理:http://jsfiddle.net/KkpwF/
我想你是在暗示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);
}
);
}
- 如何解决取消抖动的用户输入上的竞争条件
- JavaScript 中的竞争条件
- Chrome扩展 chrome.storage 如何同时进行大量获取和设置并避免竞争条件
- 修复在执行http获取请求angularJS时的竞争条件
- JavaScript img.oner更改源-竞争条件时出错
- 使用jQuery提交表单时的竞争条件
- Firefox启动的扩展,在顶级中导入时的竞争条件
- Javascript-在检查对象属性是否存在时避免异步竞争条件
- 使用独立的 AngularJS 控制器修复竞争条件
- jQuery 事件的竞争条件
- 可能的 JavaScript ajax 调用竞争条件
- JS AJAX 提前键入结果排序/竞争条件
- JavaScript 承诺和竞争条件
- 具有多个“数据”事件处理程序和竞争条件的 NodeJS 流
- 在Javascript中竞争条件可能吗?(例如:我想原子地获取和设置值)
- 如何使用getter和setter方法创建一个Angular工厂而不遇到竞争条件
- 如何使用javascript使异步ajax半同步以避免竞争条件
- Koa.js在竞争条件下产生值
- 用于循环ajax潜在竞争条件的Javascript
- 可能的PHP/Javascript竞争条件