I’m creating a website that will feature news articles. These articles will appear in two columns at the bottom of the page. There will be a button at the bottom to load additional news stories. That means that I need to be able to specify what news story to load. Server-side, I’m simply implementing this with a LIMIT clause in my SQL statement, supplying the :first parameter like so:
SELECT *
FROM news
ORDER BY `date` DESC
LIMIT :first, 1
This means that, client-side, I need to keep track of how many news items I’ve loaded. I’ve implemented this by having the function to load new information be kept in an object with a property holding the number of items loaded. I’m worried that this is somehow a race condition that I am not seeing, though, where my loadNewInformation() will be called twice before the number is incremented. My code is as follows:
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);
}
);
}
}
On page load, this is being called in the following fashion:
News.loadNewInformation('left');
News.loadNewInformation('right');
I could have implemented this in such a way that the success handler of a first call made another AJAX request for the second, which clearly would not be a race condition…but this seems like sloppy code. Thoughts?
(Yes, there is a race condition.)
Addressing Just the JavaScript
All JavaScript code on a page (excluding Web-Workers), which includes callbacks, is run “mutually exclusive”.
In this case, because newInfoItems is eagerly evaluated, it is not even that complex: both “/api/news/0” and “/api/news/1” are guaranteed to be fetched (or fail in an attempt). Compare it to this:
However, the order in which the AJAX requests complete is not defined and is influenced by both the server and browser. Furthermore, as discussed below, there is no atomic context established between the server and individual AJAX requests.
Addressing the JavaScript in Context
Now, even though it’s established that “/api/news/0” and “/api/news/1” will be invoked, imagine this unlikely, but theoretically possible situation:
B,Aexist in databasenews/0request, andnews/1requestThen, this happens:
news/0returns articleB(articlesB,Ain database)Caddednews/1returns articleB(articlesC,B,Ain database)Note that article
Bwas returned twice! Oops 🙂So, while the race-condition “seems fairly unlikely”, it does exist. A similar race condition (with different results) can occur if
news/1is processed beforenews/0and (once again) an article is added between the requests: there no atomic guarantee in either case!(The above race condition would be more likely if executing the AJAX requests in-series as the time for a new article being added is increased.)
Possible Solution
Consider fetching say,
n(2 is okay!) articles in a single request (e.g. “/api/latest/n”), and then laying out the articles as appropriate in the callback. For instance, the first half of the articles on the left and the second half on right, or whatever is appropriate.As well as eliminating the particular race-condition above by making the single request an atomic action — with respect to article additions — it will also result in less network traffic and less work for the server.
The fetch for the API might then look like:
Happy coding.