Last Sync: 2022-07-21 08:49:56

This commit is contained in:
tactonbishop 2022-07-21 08:49:56 +01:00
parent dc29317781
commit 15c834c2f1
2 changed files with 22 additions and 20 deletions

View file

@ -22,7 +22,7 @@ If there was only one thread, this would be inefficient and unworkable. Therefor
![sync-thread.svg](/img/sync-thread.svg)
To accomodate the ability to increase the scale of synchronous applications you need to be able to spawn more threads commensurate to increased ademand. This increases the resource consumption of the framework (more cores, more memory etc). Moreover it is possible to reach a point where all threads are active and no more can be spawned. In this case there will simply be delays in the return of data.
To accomodate the ability to increase the scale of synchronous applications you need to be able to spawn more threads commensurate to increased demand. This increases the resource consumption of the framework (more cores, more memory etc). Moreover it is possible to reach a point where all threads are active and no more can be spawned. In this case there will simply be delays in the return of data.
## Node as a single-threaded asynchronous architecture
@ -39,31 +39,34 @@ This is the mechanism by which Node keeps track of incoming requests and their f
Node is continually monitoring the Event Loop in the background.
A running Node application is a single running process. Like everything that happens within the OS, a process is managed by the [kernel](/Operating_Systems/The_Kernel.md) that dispatches operations to the CPU in a clock cycle. A thread is a sequence of code that resides within the process and utilises its memory pool (the amount of memory assigned by the kernel to the process). The Event Loop runs on CPU ticks: a tick is a single run of the Event Loop.
A running Node application is a single running process. Like everything that happens within the OS, a process is managed by the [kernel](/Operating_Systems/The_Kernel.md) that dispatches operations to the CPU in a clock cycle. A thread is a sequence of code that resides within the process and utilises its memory pool (the amount of memory assigned by the kernel to the Node process). The Event Loop runs on CPU ticks: a tick is a single run of the Event Loop.
### Phases of the Event Loop
The Event Loop comprises six phases. The Event Loop starts at the moment Node begins to execute your `index.js` file or any other application entry point. These six phases create one cycle, or loop, which is known as a **tick**. A Node.js process exits when there is no more pending work in the Event Loop, or when `process.exit()` is called manually. A program only runs for as long as there are tasks queued in the Event Loop, or present on the [call stack](/Software_Engineering/Call_stack.md).
The Event Loop comprises six phases. The Event Loop starts at the moment Node begins to execute your `index.js` file or any other application entry point. These six phases create one cycle, or loop, equal to one **tick**. A Node.js process exits when there is no more pending work in the Event Loop, or when `process.exit()` is called manually. A program only runs for as long as there are tasks queued in the Event Loop, or present on the [call stack](/Software_Engineering/Call_stack.md).
![](/img/node-event-loop.svg)
The phases are as follows:
1. Timers
1. **Timers**
* These are functions that execute callbacks after a set period of time. As in standard JavaScript there are two global timer functions: `setTimeout` and `setInterval`. Interestingly these are not core parts of the JavaScript language, they are something that are made available to JS by the particular browser. As Node does not run in the browser, Node has to provide this functionality. It does so through the core `timers` module.
* At the beginning of this phase the Event Loop updates its own time. Then it checks a queue, or pool, of timers. This queue consists of all timers that are currently set. The Event Loop takes the timer with the shortest wait time and compares it with the Event Loop's current time. If the wait time has elapsed, then the timer's callback is queued to be called once the [call stack](/Software_Engineering/Call_stack.md) is empty.
2. I/O Callbacks
* Node implements a non-blocking input/output interface. This is to say, writing and reading to disk (files in the Node application directory) is implemented asynchronously. The asynchronous I/O request is recorded into the queue and then main call stack can continue working as expected.
2. **I/O Callbacks**
* Once timers have been checked and scheduled, Node jumps to I/O operations.
3. Idle / waiting / preparation
* Node implements a non-blocking input/output interface. This is to say, writing and reading to disk (files in the Node application directory) is implemented asynchronously. The asynchronous I/O request is recorded into the queue and then the call stack continues.
3. **Idle / waiting / preparation**
* This phase is internal to Node and is not accessible to the programmer.
* It is primarily used for gathering informtion, and planning what needs to be executed during the next tick of the Event Loop
4. I/O polling
4. **I/O polling**
* This is the phase at which the main block of code is read and executed by Node.
* During this phase the Event Loop is managing the I/O workload, calling the functions in the queue until the queue is empty, and calculating how long it should wait until moving to the next phase. All callbacks in this phase are called synchronously in the order that they were added to the queue, from oldest to newest.
* This is the phase that can potentially block our application if any of these callbacks are slow and not executed asynchronously.
5. `setImmediate` callbacks
* During this phase the Event Loop is managing the I/O workload, calling the functions in the queue until the queue is empty, and calculating how long it should wait until moving to the next phase. All callbacks in this phase are called synchronously (although they return asynchronously) in the order that they were added to the queue, from oldest to newest.
* This is the phase that can potentially block our application if any of these callbacks are slow or do not return asynchronously.
5. **`setImmediate` callbacks**
* This phase runs as soon as the poll phase becomes idle. If `setImmediate()` is scheduled within the I/O cycle it will always be executed before other timers regardless of how many timers are present.
* This is your opportunity to grant precedence to certain threads within the Node process
6. Close events
6. **Close events**
* This phase occurs when the Event Loop is wrapping up one cycle and is ready to move to the next one.
* It is an opportunity for clean-up and to guard against memory leaks.
* This phase can be targetted via the `process.exit()` function or the close event of a web-socket.
@ -74,3 +77,6 @@ The phases are as follows:
The terms _event loop_ and _event queue_ are often used interchangeably in the literature but in fact they are distinct.
The Event Loop is the Node runtime's method of execution, the queue is the stack of tasks that are lined up and executed by the loop. We can think of the queue as being the input and the loop as what acts on the input. The queue obviously emerges from the program we write but it is scheduled, organised and sequenced by the loop.
https://blog.appsignal.com/2022/07/20/an-introduction-to-multithreading-in-nodejs.html
https://school.geekwall.in/p/Bk2xFs1DV

View file

@ -12,17 +12,15 @@ The HTTP Module allows us to create a web server that listens for HTTP requests
## Creating a server
An HTTP server is another instance of an [event emitter](Events%20module.md#event-emitters). It therefore has all the same methods as the `EventEmitter` class: `on`, `emit`, `addListener` etc. This demonstrates again how much of Node's core functionality is based on event emitters.
An HTTP server is another instance of an [event emitter](/Programming_Languages/NodeJS/Modules/Core/events.md)). It therefore has all the same methods as the `EventEmitter` class: `on`, `emit`, `addListener` etc. This demonstrates again how much of Node's core functionality is based on event emitters.
*Creating a server*
````js
const http = require('http')
const server = http.createServer() // Create server as emitter
// Register functions to run when listener listener is triggered
// Register functions to run when listener is triggered
server.on('connection', (socket) => {
console.log('new connection...')
})
@ -51,7 +49,7 @@ If we were to start the server by running the file and we then used a browser to
### Sockets and `req, res`
A socket is a generic protocol for client-server communication. Crucially it allows simultaneous communication both ways. The client can contact the server but the server can also contact the client. Our listener function above uses a socket as the callback function but in most cases this is quite low-level, not distinguishing responses from requests. It is more likely that you would initiate a `request, resource` architecture in place of a socket:
A socket is a generic protocol for client-server communication. Crucially it **allows simultaneous communication both ways**. The client can contact the server but the server can also contact the client. Our listener function above uses a socket as the callback function but in most cases this is quite low-level, not distinguishing responses from requests. It is more likely that you would initiate a `request, resource` architecture in place of a socket:
````js
const server = http.createServer((req, res) => {
@ -82,5 +80,3 @@ const server = http.createServer((req, res) => {
### Express
In reality you would rarely use the `http` module directly to create a server. This is because it is quite low level and each response must be written in a linear fashion as with the two URLs in the previous example. Instead we use Express which is a framework for creating servers and routing that is an abstraction on top of the core HTTP module.
* [Create RESTful API with Express](Create%20RESTful%20API%20with%20Express.md)