Nodejs takeaway
Tags: javascript, node
Published: 2021-09-20 22:07:32

* 1. What is Node.js and how it works?
* 2. How is Node.js better than other frameworks most popularly used?
* 3. How do you manage packages in your node.js project?
* 4. What is the Event Loop?
* 5. What is fork in node JS?
* 6. How many types of API functions are there in Node.js?
* 7. What is REPL?
* 8. How does Node.js overcome the problem of blocking of I/O operations?
* 9. What are node.js buffers?
* 10. What is node.js streams?
* 11. Why should you separate Express app and server?
* 12. Why V8 engine?
* 13. Exit codes of Node.js
* 14. What is an Event Emitter in Node.js?
* 15. Clustering
* 16. What is a thread pool and which library handles?
* 17. How are worker threads different from clusters?
* 18. How to measure the duration of async operations?
* 19 How to measure the performance of async operations?

## 1. What is Node.js and how it works?
Node.js is a virtual machine that uses JavaScript as its scripting language and **runs Chrome’s V8 JavaScript engine**. 

It's based on an **asynchronously event-driven non-blocking architecture** where I/O making it lightweight and efficient.

It **provides API to access OS-level features** such as file system, network, etc..., being used even in developing desktop applications with electron.

## 2. How is Node.js better than other
Other frameworks where developers have to use thread management.

Provides simplicity in development because of its non-blocking I/O.

And event-based model results in short response time and concurrent processing.
 
Also since we will use Javascript in both the frontend and backend the development will be much faster. 
 
And at last, there are ample libraries so that we don't need to reinvent the wheel.

## 3. How do you manage packages in your node.js project?
Mostly used are npm or yarn. Both provide almost all libraries of javascript with extended features of controlling environment-specific configurations.

To maintain versions of libs being installed in a project we use package.json and package-lock.json so that there is no issue in porting that app to a different environment.

But It can be managed by a number of package installers and their configuration file accordingly. 

## 4. What is the Event Loop?
In computer science, the event loop is a programming construct or design pattern that waits for and dispatches events or messages in a program. 

**The event loop works by making a request to some internal or external "event provider"** (that generally blocks the request until an event has arrived), **then calls the relevant event handler** ("dispatches the event"). The event loop is also sometimes referred to as the message dispatcher, message loop, message pump, or run loop.

We could think of event loop as a queue (First in first out operation), where list of events are registered, and the code associated with that event is executed.

**Node.js JavaScript Event Loop run initialization code and callbacks**. Offers a Worker Pool to handle expensive tasks like file I/O.

It uses a small number of threads to handle many clients. Because It has only a few threads, you must structure your application to use them wisely.

**Applications first complete an initialization phase, `require`'ing modules and registering callbacks for events**. 

**Then enter the Event Loop to respond incoming client requests by executing the appropriate callback**. 

**This callback executes synchronously**, and may register asynchronous requests to continue processing after it completes. 

The callbacks for these asynchronous requests will also be executed on the Event Loop.

The Event Loop will also fulfill the non-blocking asynchronous requests made by its callbacks, e.g., network I/O.

In summary, the Event Loop executes the JavaScript callbacks registered for events, and is also responsible for fulfilling non-blocking asynchronous requests like network I/O.

## 5. What is fork in node JS?
A fork in general is used to spawn child processes. In node it is used to create a new instance of v8 engine to run multiple workers to execute the code.

## 6. How many types of API functions are there in Node.js?
There are two types of API functions:

1. Asynchronous, non-blocking functions - mostly I/O operations which can be fork out of the main loop.
 
2. Synchronous, blocking functions - mostly operations that influence the process running in the main loop

## 7. What is REPL?
REPL in Node.js stands for Read, Eval, Print, and Loop, which further means evaluating code on the go.

## 8. How does Node.js overcome the problem of blocking of I/O operations?

Nodejs has an event loop that can be used to handle all the I/O operations in an asynchronous manner without blocking the main function.

if some network call needs to happen it will be scheduled in the event loop instead of the main thread (single thread). 

If there were multiple I/O calls each one will be queued accordingly to be executed separately (other than the main thread). 

Even though we have single-threaded JS, I/O ops are handled in a nonblocking way.

## 9. What are node.js buffers?
In general, buffers is a temporary memory that is mainly used by stream to hold on to some data until consumed. 

Buffers are introduced with additional use cases than JavaScript’s Unit8Array and are mainly used to represent a fixed-length sequence of bytes. 

This also supports legacy encodings like ASCII, utf-8, etc. It is a fixed (non-resizable) allocated memory outside the v8.

## 10. What is node.js streams?
Streams are instances of EventEmitter which can be used to work with streaming data in Nodejs. They can be used for handling and manipulating streaming large files(videos, mp3, etc) over the network. They use buffers as their temporary storage.

There are mainly four types of the stream:

1. Writable: streams to which data can be written (for example, `fs.createWriteStream()`).

2. Readable: streams from which data can be read (for example, `fs.createReadStream()`).

3. Duplex: streams that are both Readable and Writable (for example, `net.Socket`).

4. Transform: Duplex streams that can modify or transform the data as it is written and read (for example, `zlib.createDeflate()`)

## 11. Why should you separate Express app and server?
This ensures that the business logic is encapsulated and decoupled from the application logic which makes the project more readable and maintainable.

The server is responsible for initializing the routes, middleware, and other **application logic whereas** the app has all the **business logic** which will be served by the routes initiated by the server. 

## 12. Why V8 engine?
Google's v8 is the open-source most evolved, by a huge community helping in developing features and fixing bugs. 

The fastest as a JavaScript and WebAssembly engine till now, since it's written in c++.

And it is portable to almost every machine known

## 13. Exit codes of Node.js
Exit codes give us an idea of how a process got terminated or the reason behind termination. 

A few of them are:

1. Uncaught fatal exception - (code - 1)
There has been an exception that is not handled

2. Unused - (code - 2)
This is reserved by bash

3. Fatal Error - (code - 5)
There has been an error in V8 with stderr output of the description

4. Internal Exception handler Run-time failure - (code - 7)
There has been an exception when bootstrapping function was called

5. Internal JavaScript Evaluation Failure - (code - 4)
There has been an exception when the bootstrapping process failed to return function value when evaluated

## 14. What is an Event Emitter in Node.js?
EventEmitter is a Node.js class that includes all the objects that are basically capable of emitting events. 

This can be done by attaching named events that are emitted by the object using an eventEmitter.on() function. 

Thus whenever this object throws an even the attached functions are invoked synchronously.
```
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
 console.log('an event occurred!');
});
myEmitter.emit('event')
```

## 15. Clustering.
Node.js applications run on a single processor, which means that by default they don’t take advantage of a multiple-core system. 

Cluster mode is used to start up multiple node.js processes thereby having multiple instances of the event loop. 

When we start using cluster behind the scene multiple processes are created but there is also a parent process called the cluster manager which is responsible for monitoring the health of the individual instances of our application.

## 16. What is a thread pool and which library handles it?
The Thread pool is handled by the libuv library. 

libuv is a multi-platform C library that provides support for asynchronous I/O-based operations such as file systems, networking, and concurrency.

## 17. How are worker threads different from clusters?

1. Cluster: 
  - There is one process on each CPU with an IPC to communicate.
  - In case we want to have multiple servers accepting HTTP requests via a single port, clusters can be helpful. 
  - The processes are spawned in each CPU thus will have separate memory and node instance which further will lead to memory issues.

2. Worker threads:
  - There is only one process in total with multiple threads. 
  - Each thread has one Node instance (one event loop, one JS engine) with most of the APIs accessible.
  - Shares memory with other threads (e.g. SharedArrayBuffer).
  - This can be used for CPU-intensive tasks like processing data or accessing the file system since NodeJS is single-threaded, synchronous tasks can be made more efficient leveraging the worker's threads.


## 18. How to measure the duration of async operations?
Performance API provides us with tools to figure out the necessary performance metrics. A simple example would be using async_hooks and perf_hooks. This would give us the exact time it took to execute the callback.
```
'use strict';
const async_hooks = require('async_hooks');
const {
 performance,
 PerformanceObserver
} = require('perf_hooks');
const set = new Set();
const hook = async_hooks.createHook({
 init(id, type) {
if (type === 'Timeout') {
  performance.mark(`Timeout-${id}-Init`);
  set.add(id);
}
 },
 destroy(id) {
if (set.has(id)) {
  set.delete(id);
  performance.mark(`Timeout-${id}-Destroy`);
  performance.measure(`Timeout-${id}`,
                      `Timeout-${id}-Init`,
                      `Timeout-${id}-Destroy`);
}
 }
});
hook.enable();
const obs = new PerformanceObserver((list, observer) => {
 console.log(list.getEntries()[0]);
 performance.clearMarks();
 observer.disconnect();
});
obs.observe({ entryTypes: ['measure'], buffered: true });
setTimeout(() => {}, 1000);
```

## 19 How to measure the performance of async operations?
Performance API provides us with tools to figure out the necessary performance metrics. 

A simple example would be:
```
const { PerformanceObserver, performance } = require('perf_hooks');
const obs = new PerformanceObserver((items) => {
 console.log(items.getEntries()[0].duration);
 performance.clearMarks();
});
obs.observe({ entryTypes: ['measure'] });
performance.measure('Start to Now');
performance.mark('A');
doSomeLongRunningProcess(() => {
 performance.measure('A to Now', 'A');
 performance.mark('B');
 performance.measure('A to B', 'A', 'B');
});
```