0

I often read that you don't have to worry about race conditions in javascript as it's single-threaded. But I believe that it's because of Run-to-completion nature of event loops. Javascrit could still have concurrency issues if it did not had the "Run-to-completion" feature.

Let's consider this code snippet:

1  var pending = [];

2  document.getElementById("submitBtn").addEventListener(function() {
3      var val = document.getElementById("textBox").value;
4      pending.push(val);
5  });

6  setInterval(function() {
7     processValues(pending);
8     pending = [];
9  }, 3000);

Asume that there was no such feature in javascript "Run-to-completion" and any event could be pre-empted to run another event/code.

Now suppose line 7 gets executed and suddenly the event gets pre-empted to process the event at line 3. After executing line 3 & 4, the previous event is resumed from line 8. Now when line 8 gets executed, the newly added value in pending will be lost because it's neither processed by processValues function not it's in the pending array.

A race condition occurred even though it is single-threaded. So, it's not right to say that javascript does not have race conditions because it's single-threaded? Specifically, it's because of Run-to-completion feature of javascript?

EDIT

Apparently, there can be race conditions in javascript. What I was referring to is the certain class of race conditions that does not occur because of single-threaded (or because of Run-to-completion?) nature of javascript. For example, the one I described above.

Uzair Farooq
  • 2,402
  • 3
  • 24
  • 37
  • Where did you read that? Race conditions are common in asynchronous code. – Jivings Apr 25 '15 at 15:52
  • 1
    Race conditions are possible in the asynchronous parts of javascript, websockets etc. – adeneo Apr 25 '15 at 15:52
  • A thoughtful answer has already been provided for this, if you're curious: http://stackoverflow.com/questions/21463377/can-we-have-race-conditions-in-a-single-thread-program – bvaughn Apr 25 '15 at 15:55
  • @Jivings @ adeneo check the answer to the question http://stackoverflow.com/questions/21467325/javascript-thread-handling-and-race-conditions – Uzair Farooq Apr 25 '15 at 15:55
  • @brianvaughn the answer states "Race conditions can only occur between two or more threads" which I don't think is true in case of scripting languages. It confused me. – Uzair Farooq Apr 25 '15 at 16:02
  • @UzairFarooq: If so, the answer is wrong. :-) Throw async into the mix, and you have race conditions in single-threaded code. – T.J. Crowder Apr 25 '15 at 16:17
  • I think "race condition" is a *term* that only applies to multi-threaded languages. A similar concept exists in single threaded, event-based languages wrt reentry (e.g. when the order of event handlers is not known) but it's technically *not* a race condition, just a similar thing. – bvaughn Apr 25 '15 at 16:33
  • If it is a really single threaded implementation, then you can only process one event after each other, so not very responsive and while you are doing calculations the events just have to sit in the queue, GUI is therefore rarely single threaded. – maraca Apr 25 '15 at 16:37

1 Answers1

2

Yes, we have race conditions in single-threaded JavaScript. Just not as many as in multi-threaded code (provided you don't use alert or confirm, more below).

You've started by saying "assume no run-to-completion feature" and then described a race condition relying on that. But that race condition cannot happen because, as you say, JavaScript has run-to-completion.

While it's true that there is a class of race conditions we don't have to worry about in JavaScript, there are still plenty we do have to worry about. Async code, for instance, will always have the potential for race conditions. (So that's ajax calls, messages from web workers, etc.)

Here's an example of a mistake you see commonly, which is a real-world race condition:

var img = document.createElement('img');
img.src = "kittens.png";
img.onload = function() {
    console.log("It loaded");
};
document.body.appendChild(img);

That's safe, right? Wrong. Just because JavaScript is run single-threaded, it doesn't mean the browser is single-threaded. When the browser sees img.src = "kittens.png";, if the image is in cache, it is perfectly within its rights to fire the load event on that img: That event will look for any handlers, not find any, and so not queue any callbacks to run once the current code completes — and we don't see the "It loaded" message.

And while that's a browser-based example, it's an example of a general principal: Just because the host environment runs a single main JavaScript thread, that doesn't mean that the host enviroment isn't multiply-threaded, and that that multiple threading can have consequences for our single-threaded code.

That's just one example. But it's true we're safe from some others. For instance, if we change the code above:

var img = document.createElement('img');
img.onload = function() {
    console.log("It loaded");
};
img.src = "kittens.png";
document.body.appendChild(img);
doSomethingElse();

...we know doSomethingElse will be called before "It loaded" runs, barring some unpleasant edge cases on certain browsers (I'm Looking At You, Mozilla) around the alert and confirm functions; bobince covers those in this other answer. (TL;DR - At least some versions of Firefox will fire ajax completion callback while waiting for the user to dismiss an alert.)

Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Nice answer. Although I think the problem is that javascript is not really single threaded. If you look at a simple Java program not starting any threads or anything and no asynchronous methods (actually asynchronous implies multi threaded I think) THEN it is impossible to create race conditions, right? – maraca Apr 25 '15 at 16:06
  • @maraca: Well, **JavaScript**, the language, is completely silent on threading. The only thread guarantees are provided by the host. *JavaScript on web browsers* has access to a single UI thread and X number of web workers. Ignoring web workers, browser-based JavaScript really is single-threaded barring the issues I mentioned at the end of my answer, and web workers were very intelligently designed to use a message event model and worker isolation to avoid breaking that. Similarly, JavaScript on, say, NodeJS is guaranteed a single thread by NodeJS. JavaScript on the JVM (Rhino, Nashorn) isn't. – T.J. Crowder Apr 25 '15 at 16:09
  • @T.JCrowder yes, this is exactly my point, you can't apply this to JavaScript but it might be true for other languages. – maraca Apr 25 '15 at 16:13
  • @T.J.Crowder You're right, race conditions can occur in javascript. See my updated question. – Uzair Farooq Apr 25 '15 at 16:28