As far as I know, it has always held true that javascript execution within a window in a web browser has been single threaded. Sure, you could fire off background requests, set timers and so on, but all callbacks/events that trigger user script execution had to wait their turn in an event queue.

The nice thing about this is if you make sure all of your global application state is consistent at the end of a function, that means it will be consistent at the start of your next function. With the introduction of Internet Explorer 7, this is no longer a safe assumption, as the inline javascript on this page demonstrates. Microsoft has decided to make things this way out of malice or stupidity, but the net result is that you end up wishing for synchronization constructs that don't exist.

I haven't yet checked which of the following scenarios are true yet, but here is my thinking on both of them:

If you don't feel up to avoiding race conditions, you can always just make sure not to call any functions which aren't safe to be called re-entrantly from your callback handlers. This is the approach that the signal facility that a lot of c runtimes gives you. Have fun trying to figure out what functions (either provided by the browser or that you wrote yourself) aren't safe to be called re-entrantly.