Let me check if I got this.
Node.js is single-threated, so its code can't run in parallel, but its I/O can be concurrent. We use asynchronous javascript functions for that. So that's why I/O is non-blocking.
Node.js keeps a single thread for your code......however, everything runs in parallel, except your code.
Doing a "sleep" for example will block the server for one second. - single-threated code
All I/O is evented and asynchronous, so the following won't block the server: c.query( 'SELECT SLEEP(20);', ....
- the "sleep" is inside an asynchronous function, the query - non-blocking I/O
(from here )
To manage the incoming requests, Node implements the "event loop".
An event loop is "an entity that handles and processes external events and converts them into callback invocations". So I/O calls are the points at which Node.js can switch from one request to another. At an I/O call, your code saves the callback and returns control to the node.js runtime environment. The callback will be called later when the data actually is available.
(from here)
So I/O is non-blocking because Node can do something else instead of waiting for some I/O to finish.
If a request can take too long to answer, Node will assign to that request a thread from a thread pool.
That Thread is responsible for taking that request, process it, perform Blocking IO operations, prepare response and send it back to the Event Loop
Event Loop in turn, sends that Response to the respective Client. (from here )
- So, if there a lot of simple requests, the I/O is non-blocking and all the callbacks of these requests answer really fast.
(from this point forward I am not sure I got it correctly)
- A lot of simple requests and a complex one. The complex one could be a heavy task, an image-resize algorithm or whatever takes time. Each request is in a asynchronous function , node will define a thread for the complex one. Most of the simple ones will respond immediately. The complex one will take some time, inside its own thread, while the simple ones still responding (cause non-blocking). But the callbacks in the event loop are queued in a specific order (FIFO, right?).
In a loop, the queue is polled for the next message (each poll referred to as a “tick”) and when a message is encountered, the callback for that message is executed. The calling of this callback function serves as the initial frame in the call stack, and due to JavaScript being single-threaded, further message polling and processing is halted pending the return of all calls on the stack. Subsequent (synchronous) function calls add new call frames to the stack (from here)
So the callbacks of the simple requests that come after the complex's callback will take some time to respond, because the complex's callback will take a lot of time.
A lot of complex requests , each inside its own asynchronous function. If each request takes , say, 1 sec to respond and we have 10000 responds, the time sums up. They all eventually sum up in the single-threated node that uses the event loop. Inside the event loop, each callback that takes a lot of time to respond is queued behind another callback that takes a lot of time to respond.
I think the above describes Grant's problem here . That was the first article that I red about node's cons and I still dont know if I got it correctly. So,
Our Node service may have handled incoming requests like champ if all it needed to do was return immediately available data.
But
Node is single-threaded which means none of your code runs in parallel. I/O may not block the server but your code certainly does. If I call sleep for 5 seconds, my server will be unresponsive during that time.
Grant find herself with a lot of requests that took time because an amazon service was slow
...was waiting on a ton of nested callbacks all dependent on responses from S3 (which can be god awful slow at times)
And then the event loop killed everything
In a loop, the queue is polled for the next message (each poll referred to as a “tick”) and when a message is encountered, the callback for that message is executed. The calling of this callback function serves as the initial frame in the call stack, and due to JavaScript being single-threaded, further message polling and processing is halted pending the return of all calls on the stack. Subsequent (synchronous) function calls add new call frames to the stack..... when any request timeouts happened, the event and its associated callback was put on an already overloaded message queue. While the timeout event might occur at 1 second, the callback wasn’t getting processed until all other messages currently on the queue, and their corresponding callback code, were finished executing (potentially seconds later).
I dont know if I got this correctly. Please, feel free to point out my errors and help me get the whole thing right.
Thanks