NodeJS

Intro

Agenda

  • What is Node.js

  • How Node.js works

  • When to use Node.js

  • Node.js installation. NVM

  • Package manager:  NPM / Yarn

  • Global objects

  • Node.js modules

  • Core modules

What is                     ?

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

What is NodeJS?

What is V8 JavaScript engine?

How V8 works?

V8 JS Engine

Open-source high-performance JavaScript and WebAssembly engine, written in C++. It is used in Chrome and in Node.js, among others. It implements ECMAScript and WebAssembly

  • Heap Memory allocation

  • Call stack execution context

  • Orinoco Garbage Collector

  • TurboFan Optimization controller -  takes this bytecode and generates machine code from it. (JIT)

  • Ignition JS Interpreter - generates bytecode from this syntax tree using the internal V8 bytecode format.

  • Liftoff WebAssembly

libuv

libuv is a multi-platform C library that provides support for asynchronous I/O based on event loops. It supports epoll, kqueue, Windows IOCP, and Solaris event ports. It is primarily designed for use in Node.js but it is also used by other software projects.

Network I/O

File I/O

DNS

66.8% of developers rated Nodejs as the most loved tool in Stackoverflow Developer Survey Report 2020

85% of Nodejs developers use it for web app development, and the other 43% use it for enterprise-grade applications

51.4% of developers regarded Nodejs as the most-used tool earlier in the 2020

 How                      works        

JavaScript is “single-threaded” because JavaScript works on “Event Loop”

NodeJS is NOT “single-threaded” as it has a libuv threadpool in its runtime.

The chefs are the libuv threadpool and OS Async Helpers.

The waiter is the V8 engine and the Event Loop

The JavaScript code you want to be executed is the food

Node.js restorant

Comparison with other platforms

w3techs.com statistic

The following server-side programming languages are used by less than 0.1% of the websites

w3techs.com statistic

The following server-side programming languages are used by less than 0.1% of the websites:

Miva Script

Lasso

C

Lisp

C++

Smalltalk

Tcl

Haskell

Go

Ada

Strong static typing

Dynamic typing / weak static

Event-loop / single threaded

Threads

Mandatory exception handling

Optional exception handling

OOP / Patterns

Proto / FP / Reactive/ NonBlocking

Dynamic typing / weak static

event loop

sync execution (threads) / reactive libs

Optional exception handling

Used by 79.1% of all websites (w3techs)

Strong static typing

Threads

Mandatory exception handling

OOP / Patterns

Advantages of using Node.js

Ability to use the same language on the client and server-side

Speed of work

The lightness of the system allows us to create lightweight applications

The opportunity to use JavaScript syntax

A Node package manager that you can use to install and search for packages

Constant technology development (e.g., TypeScript is being developed now)

Single thread Event loop to process requests

Disadvantages of Node.js

Poor of processing large data volumes

Low CPU-handling capacities

Node.js vs JS problem

  • Inconsistent models
  • Lack of semantic standardization
  • Frequent changes

Messy syntax

When to use Node.js

Here are some questions to answer

What kind of project are we dealing with?

What kind of product we expect to deliver?

What is the project's reach?

What resources do we currently have?

What is the situation on the market?

What are our main performance criteria?

The main areas, where Node.js is more suitable:

Backend for Front-end

Enterprise web-applications

SSR (Server side rendering)

Message Servers and Event Broadcasting (Chats, Games, Interactive)

Build tools (webpack, babel and etc)

Desktop web-application (Electon: VS Code, Slack)

Microcontrollers

What is Node.js used for?

The environment can support intense traffic of multiple short messages or chatrooms in real-time messaging



Real-time application

Ability to process real-time flows - benefited from its event-driven, non-blocking model

 

 

 

Collaborative tools

The term “streaming” means exactly that – sending large amounts of data in smaller packages instead of a single batch. Node.js is perfectly suited for this task with built-in modules supporting data streaming and allowing to creation of both readable and writable data streams.

 

 

 

Data streaming applications

The superb scalability supported by Node.js answers the “why Node.js” question for apps required to withstand high peak loads.

 

 

 

Applications relying on scalability

Node.js installation. NVM

Node.js installation

LTS vs Current

Releases that receive Long-term Support, with a focus on stability and security.

Under active development. Code for the Current release is in the branch for its major version number

NVM

nvm stands for Node Version Manager. As the name suggests, it helps you manage and switch between different Node versions with ease. It provides a command-line interface where you can install different versions with a single command, set a default, switch between them and much more.

Package manager: NPM/Yarn

npm package manager

  • the website
  • the Command Line Interface (CLI)
  • the Registry

npm init

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

npm install

{
  "name": "user-service",
  "version": "0.0.1",
  "description": "",
  "author": "",
  "license": "UNLICENSED",
  "scripts": {
    "prebuild": "rimraf dist",
    "build": "nest build",
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
    "start": "nest start",
    ...
  },
  "dependencies": {
    "@nestjs/common": "^7.6.15",
    "@nestjs/core": "^7.6.15",
    "@nestjs/mapped-types": "*",
    "@nestjs/platform-express": "^7.6.15",
    ...
  },
  "devDependencies": {
    "@nestjs/cli": "^7.6.0",
    "@nestjs/schematics": "^7.3.0",
    "@nestjs/testing": "^7.6.15",
    ...
  }
}

package-lock.json

{
  "name": "user-service",
  "version": "0.0.1",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "@angular-devkit/core": {
      "version": "11.2.6",
      "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.2.6.tgz",
      "integrity": "sha512-3dA0Z6sIIxCDjZS/DucgmIKti7EZ/LgHoHgCO72Q50H5ZXbUSNBz5wGl5hVq2+gzrnFgU/0u40MIs6eptk30ZA==",
      "dev": true,
      "requires": {
        "ajv": "6.12.6",
        "fast-json-stable-stringify": "2.1.0",
        "magic-string": "0.25.7",
        "rxjs": "6.6.3",
        "source-map": "0.7.3"
      },
      "dependencies": {
        "rxjs": {
          "version": "6.6.3",
          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
          "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
          "dev": true,
          "requires": {
            "tslib": "^1.9.0"
          }
        },
        ...

Versioning

  1. A normal version number MUST take the form X.Y. X is the major version and Y is the minor version.
  2. Minor version MUST be incremented for any release which maintains backwards compatibility to the public API.
  3. Major version MUST be incremented if any backwards incompatible changes are introduced to the public API.
  4. When compatibilty with SemVer tooling is required, it is acceptable to add a ‘.0’ patch version, e.g. 2.1.0, but normally that should be avoided.

Yarn

Global objects

NodeJS Globals

Global object in a browser

What will happen when you type the following code in a browser console?

// console.log(this) or just
 this

And the correct answer is - we will get the full global object Window

Global object in a browser

And some examples:

// standard way to use console.log
console.log('hello');

// equal to
window.console.log('hello');

// custorm variable created like that 
window.myVar = 'JavaScript';

// we can access like that
console.log(myVar);

Global object in NodeJS

There is no global object window, but we have - global namespace Object

// standard way to use console.log
console.log('hello');

// equal to
global.console.log('hello');

// custorm variable created like that 
global.myVar = 'JavaScript';

// we will get 'undefined'
console.log(myVar);

// this is pointing to the global
console.log(this);


// common functions
global.require('http'); // equal to - require('http');

global.process; // equal to - process; 

global.setImmediate(cb); // equal to - setImmediate(cb);

Globals in NodeJS

Commonly used:

  • __dirname
  • __filename
  • module
  • exports
  • Buffer (class)
  • URL (class)
  • URLSearchParams (class)
  • and etc

Node.js modules

Modules: CommonJS modules

In the Node.js module system, each file is treated as a separate module

const circle = require('./circle.js');

console.log(`The area of a circle of radius 4 is ${circle.area(4)}`);

Here are the contents of circle.js:

const { PI } = Math;

exports.area = (r) => PI * r ** 2;

exports.circumference = (r) => 2 * PI * r;

Modules

Module 1

Module 2

Module 3

Variables local to the module will be private because the module is wrapped in a function by Node.js (IIFE).

Modules

app.js

Every file is a module.
Every variable and function defined in the file are in the scope of this module and not available outside.

Modules: create a new one

logger.js

const loggerUrl = 'http://mylogger.io/log';

function logger(message) {
  // Send an HTTP request
  console.log(message);
}

module.exports.log = logger;

// we can export URL as well
// mostly should not be done,
// as it's implementation details
module.exports.LOGGER_URL = loggerUrl;

Modules: loading a module

app.js

const logger = require('./logger');

function app() {
  	// some logic can be there
  	
    logger.log('log my message');
}

app();

Modules: another way to do the same

const logger = require('./logger');

function app() {
  	// some logic can be there
  	
    logger('log my message');
}

app();
const loggerUrl = 'http://mylogger.io/log';

function logger(message) {
  // Send an HTTP request
  console.log(message);
}

module.exports = logger;

Modules: CommonJS modules

The module.exports property can be assigned a new value (such as a function or object).

const Square = require('./square.js');
const mySquare = new Square(2);
console.log(`The area of mySquare is ${mySquare.area()}`);

The square module is defined in square.js:

module.exports = class Square {
  constructor(width) {
    this.width = width;
  }

  area() {
    return this.width ** 2;
  }
};

Modules: require(X)

addTwo.mjs

app.mjs

Modules: ECMAScript modules

// addTwo.mjs
function addTwo(num) {
  return num + 2;
}

export { addTwo };
// app.mjs
import { addTwo } from './addTwo.mjs';

// Prints: 6
console.log(addTwo(4));

Available from NodeJS v.12.12.0

Core modules

Common information

  • Core modules are described in NodeJS documentation
  • Core modules are always preferentially loaded if their identifier is passed to require()
  • Core modules can also be identified using the node: prefix(Added v16.0.0)

Assert

The assert module provides a set of assertion functions for verifying invariants.

const assert = require('assert/strict');

// This fails because 1 !== '1'.
assert.deepStrictEqual({ a: 1 }, { a: '1' });
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
//   {
// +   a: 1
// -   a: '1'
//   }

assert.ok(typeof 123 === 'string');
// AssertionError: The expression evaluated to a falsy value:
//
//   assert.ok(typeof 123 === 'string')

Util

The util module supports the needs of Node.js internal APIs. Many of the utilities are useful for application and module developers as well.

const util = require('util');
const fs = require('fs');

const stat = util.promisify(fs.stat);

stat('.').then((stats) => {
  // Do something with `stats`
}).catch((error) => {
  // Handle the error.
});

util.format('%s:%s', 'foo', 'bar', 'baz');
// Returns: 'foo:bar baz'

util.types.isDate(new Date());  // Returns true

Path

The path module provides utilities for working with file and directory paths.

const path = require('path');

path.parse('/home/user/dir/file.txt');
// Returns:
// { root: '/',
//   dir: '/home/user/dir',
//   base: 'file.txt',
//   ext: '.txt',
//   name: 'file' }

path.format({
  root: '/ignored',
  dir: '/home/user/dir',
  base: 'file.txt'
});
// Returns: '/home/user/dir/file.txt'

path.resolve('/foo/bar', './baz');
// Returns: '/foo/bar/baz'

Process

The process object is a global that provides information about, and control over, the current Node.js process.

const process = require('process');

// print process.argv
process.argv.forEach((val, index) => {
  console.log(`${index}: ${val}`);
});

process.on('uncaughtException', (err, origin) => {
  fs.writeSync(
    process.stderr.fd,
    `Caught exception: ${err}\n` +
    `Exception origin: ${origin}`
  );
});

process.on('exit', (code) => {
  console.log('Process exit event with code: ', code);
});

process.exit(1);

File system

The fs module enables interacting with the file system.

const { unlink } = require('fs/promises');

(async function(path) {
  try {
    await unlink(path);
    console.log(`successfully deleted ${path}`);
  } catch (error) {
    console.error('there was an error:', error.message);
  }
})('/tmp/hello');
const { unlinkSync } = require('fs');

try {
  unlinkSync('/tmp/hello');
  console.log('successfully deleted /tmp/hello');
} catch (err) {
  // handle the error
}

Synchronous example:

HTTP

HTTP server

const http = require('http');

// Create an HTTP server
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('okay');
});

server.listen(8000);
const http = require('http');

http.get('http://localhost:3000', { agent }, (res) => {
  res.on('data', (data) => {
  // Do nothing
  });
});

HTTP request

Q & A