join(user) {
if(this.room.length === 2) throw new Error('The room is full');
this.room.push(user);
};
If asynchronicity goes on a 'function' basis, this code is 100% bulletproof. There's no way there can be more than two users in a room.
If asynchronicity goes on a 'per line' basis, this code may fail. Why? Because if three users enter the room at the same time, the following may happen in a 10ms interval:
1ms: Room is empty. Let User A in, push to array.
4ms: Room has one user.
5ms: User B asks to join.
6ms: User C asks to join.
7ms: Check array for length (1).
8ms: Check array for length (1).
9ms: Push user B to array because room length is 1.
10ms: Push user C to array because room length is 1.
15ms: Now room has 3 users and the max was two.
If asynchronicity goes on a 'per line' basis, how do I avoid the previous example to happen in a real scenario? Sorry if I haven't called things by their name, but I can't think of a better way to explain this.
The comments suggest (but don't say for sure and in a clearly manner) that 'instances' of the same function won't ever overlap each other. What about different functions pointing to the same object/array?
join(user) {
if(GLOBAL.room1.length === 2) throw new Error('The room is full');
GLOBAL.room1.push(user);
};
join2(user) {
if(GLOBAL.room1.length === 2) throw new Error('The room is full');
GLOBAL.room1.push(user);
};
Javascript is synchronous per event (a greater scope than a function or a line). This excludes any asynchronous operations you start yourself. They will start and then complete some time later with their own event (see discussion of events later on here). Synchronous code for an event (like what you show) will run entirely to completion before the next event can be run.
Your javascript in nodejs runs as single-threaded and event driven. That means that one a piece of Javascript starts executing, it will finish before any other events can be processed. As such, a function runs and completes before anyone can call it again (assuming it doesn't call itself) so you do not have the typical types of race conditions that can exist in a multi-threaded environment.
Javascript in node.js is single-threaded and it will run an entire event handler to completion (all functions in that event handler) before running the next event.
Javascript's single threadedness is not per line or per function. It's per event. So, in this case it appears you're probably handling an incoming socket.io message. That means that all code in that incoming message event handler will run before ANY other incoming messages can be processed. Only when your event handler returns control back to the system (by returning from its event handler function) will nodejs get the next event in the event queue and call its event handler.
So, let's say that three users are all asking to join the same room at about the same time and examine that scenario to explain further how this works.
Hopefully from this description of how things are processed, you can see that your check of the room length does not have any possible race conditions. The adding of a user to the room is single threaded so it will start, progress and complete before any other requests to join the room can be processed. This single-threaded nature (while occasionally a limiting feature) vastly, vastly simplifies nodejs programming because it removes many of the possible causes of race conditions that multi-threaded programming has.
Let's look at your sequence with my comments on each step:
If the first request is not done processing yet, this request will be put in the event queue until that first request is done. If the first request is done, then this request will start processing.
Assuming the second request takes more than 1ms to process so it's not done yet, this request will go in the event queue and will not be processed until both of the first two requests are completely done.
I don't understand what this step is meant to be. If this is part of processing the second request, then the second and third requests are still in the event queue and cannot run until the first one is done.
Same as previous comment.
This is flawed logic. Because of the event-queue and the single threaded nature of nodejs Javascript, the userB and userC requests do not run until the userA request is done. Thus, the room length is always accurate when any request runs. Multiple requests like this do not run at the same time.