[Please note that this post was written a long time ago, and that it merely speaks of a proof-of-concept.
If you are really concerned about concurrency issues in writing to localStorage (and chances are that it's not
actually a real problem you have to worry about in practice), I wouldn't suggest using the methods described here.
Rather, you should probably look at the storage event
and use it for a message-passing approach.]

The specification says there is no problem

There must be [...] at most one event loop per unit of related similar-origin browsing contexts.

Most simply, this means that in the JavaScript that's executing in a single page, no two functions are
executing at the same time. If a function foo() is running for five seconds, I can click on the page
as often as I want during those five seconds; the click handler will not be fired until afterfoo()
has returned.

Even better, this also holds for the JavaScript in all pages that have access to each other's data, e.g.
an IFRAME, its parent, and another window that this parent opened via window.open() – they still
share an event loop.

That's why the following code doesn't have to worry about a change that another thread would make to
elem.innerHTML between the test and the assignment:

Even though the DOM may be accessed by lots of different pieces of JavaScript, the event loop model
guarantees that this shared memory isn't suddenly changed by someone else while you're in the middle
of working with it.

If two pieces of JavaScript run in different event loops, there are two possibilities:

They're from the same domain, but they don't know about each other. If a user opens two pages on the same site in two different browser
tabs, these pages don't have access to each other's window object, and thus they don't have shared data
in which they could trip over each other.

They know about each other, but they come from different domains (e.g. a cross-domain IFRAME). In that case,
the cross-origin restrictions prevent the page from accessing the other's data for security reasons, so there's
no shared memory either. The two may be able to communicate with each other (via postMessage),
but message passing has no concurrency problems, since you're just sending copies of data around.

All good! No threading issues in JavaScript. Happy end of story. … Right?

Enter localStorage.

It's awesome. If you're carful.

Supported in all modern browsers (even in IE8), the HTML5 localStorage is an awesome way to store per-domain data
in the user's browser, for example for caching, draft-saving, and lots of other useful stuff. The localStorage is
shared by all pages coming from the same domain, so your web app only has to load all the user's settings from the
server once, namely when they open a page for the first time, and store them locally. On subsequent pageviews, you can
just pull the data from the localStorage.

All good! Store data locally, without the need for cookie hacks. Happy end of story. … Well, you probably
know where I'm going.

The localStorage of course is a piece of memory that is shared among different event loops. Several browser windows
that do not know about each other, and thus may have different event loops, still use the same localStorage if they come
from the same domain.

Between retrieving the value at (1) and storing the new value at (2), another piece of JavaScript could have changed the
content of localStorage["myKey"]. These changes will be overwritten.

In my testing, this issue actually occured in Chrome and in Opera, while (at least in my simple tests) Firefox, Internet
Explorer and Safari did not show this problem. I don't know whether this is because the test pages were using the same
event loop, or the browser was holding the storage mutex for a
longer time, or for different reasons.

Now, if you're careful, the chance of this happening is pretty low. On the Stack Exchange Chat,
we have for a long time been using the localStorage as a way for several chat room tabs the user may have opened to
communicate with each other, so that only one of the tabs has to talk
to the server, and can pass the received data on to the other tabs. This communication is also used for a few small
other niceties; e.g. when a user closes a notification in one tab, this is communicated to the other tabs, so they can
close this notification as well.

Know what the other ones are up to

This cross-tab communication happens via a JSON-serialized array of message objects that is stored in the localStorage
under a fixed key. When one tab wants to broadcast a new message, it pulls the current content from the storage,
deserializes it into an array, appends the new message object, re-serializes it, and puts it back into the storage (that last step
causes a storage event to be fired in all open tabs from that domain, so they know to look for new data).

So, how do we make sure that two tabs broadcasting a message at the same time don't overwrite each other's changes?

Most importantly, by making this strictly fire-and-forget. There's only broadcasting of messages. We never ever send
responses or confirmations. If one browser tab would send a message saying "Hey, anyone else there?", and three other tabs
immediately answer "Yes, I'm here", these three responses happen so close to each other that the chance for overwriting
messages increases.

Another thing is that the messages are only broadcast when some event happens; usually a click or an AJAX request.
The chance of two of these happening in such a short succession (and we're talking really short; it's not like storing
a new message takes very long) is extremely low.

However, this cross-tab communication has been working great, and in order to improve it and utilize it in even more places,
a back-and-forth communication (i.e. the responses I ruled out above) would be nice to have.

That's why today, I took a look at locking algorithms, and whether I could have a chance to make this retrieve-and-resave loop
not be dangerous, and I actually managed to get something working. You can find the (yet very undocumented) code in this Bitbucket
repository.

Finally some code!

This algorithm has the huge advantage that it doesn't require any process to know how many other processes there are accessing the
same data, as long as each one has its own unique ID. I create these IDs from both a time stamp and a random number; since this
happens on page load (or rather, when the JS file is executed), the chances of collisions are purely theoretical.

The disadvantage of this algorithm is that it has a timing requirement. In case of a lock contention, it makes the assumption
that the time spent in the critical section has a fixed upper bound. But since the only thing we do in the critical section
is check and set the mutex lock owner, I considered 40ms to be a very generous bound.

The usage is pretty simple:

LockableStorage.lock("myKey",function(){storeAnotherNumber(42);});

Assuming that all the code (on this domain) writing to localStorage["myKey"] uses this locking functionality, there should be
no overwriting of changes. If you're only reading, you don't need to lock (the specification guarantess the atomicity of both reads
and writes).

The function LockableStorage.lock takes a string (the localStorage key), and a callback function that is called asynchronously once
the lock is aquired (it will be released again when this function exits).

There is a third (optional) argument maxDuration. This is the time, in milliseconds, that the callback function guarantees not to take
longer than. It defaults to 5000 (you're hopefully not executing blocking functions that take longer than 5 seconds, are you?). This is necessary
because a browser may close the page at any time. If this happens while there's a lock on a localStorage key, the lock will never be
released. That's why locking has a maximum duration, so it can't block forever. Think of the classic action movie quote “If I'm not back in ten
minutes, assume I'm dead” and its variants.

Once again, here's the link: bitbucket.org/balpha/lockablestorage. Just for the record:
This is very experimental, I was just playing around, the code is very undocumented so far,
and I have no idea what I'm talking about when it comes to locking algorithms. But I hope you still find it interesting.