Node

JavaScript meets back-end server hosting

Monday, Apr 13, 2020

Node.js

Node.js provides server-side functionality in familiar Javascript syntax and an asynchronous model. To be clear, Node.js is not a programming language. It adds features to Javascript that allow developers to write server-side code in familiar front-end language.

How It Works

As an interpreted language (like Python), Javascript requires a runtime engine to be run. How Node js functions as a server side language is its runtime engine allows it to interact with a server. In the browser, a Javascript engine provides access to Web Platform APIs and the window HTML (DOM). Node uses Google’s V8 Javascript engine instead to access files, send data, and provide other server capabilities. The V8 engine powers Chrome, but there are other engines out there:

  1. Firefox uses SpiderMonkey
  2. Safari uses JavaScriptCore
  3. IE uses who on 🌍 cares

The Chrome V8 Javascript engine provides C++ bindings for Javascript. The V8 Engine then passes events and data between the server and client.

Let’s take a small example. Javascript has no concept of accessing system files, but in Node.js, we gain this functionality through modules. We’ll get to modules later, but here’s a small example of what you can do with Node.js using the built in filesystem module fs.

Alternatively, you can run this in the node console. In your terminal, typing node creates a shell utilizing a Read Evaluate Print Loop (REPL)

What this means is that as expressions are evaluated, their return value is printed in the console. You can invoke the REPL by just typing node in your terminal. Then, you can test what expressions are doing. Which is useful for debugging expressions and playing around with Javascript.

/* Enter the number 4, then press enter */
4 // <Enter>
++_ // Increment the previous expression by 1

Warning: In this example, we used _ , which refers to the previous expression. However, this feature has been deprecated, and you’ll get an annoying warning if you try to use it.

You’ll notice that the return value is printed below each statement executed:

v = "Vim"
// => 'Vim'
e = "Emacs"
// => 'Emacs'
console.log("I'm a pro since I use ", v)
// => I'm a pro since I use Vim

You can exit the REPL by pressing ^D or ^C^C.

The process variable, only accessible to you in Node, not in the browser. process is a list of current tasks that Node is executing.

Module System

Modules in Nodejs are essentially Javascript libraries. There are quite a few built-in libraries available by default in Nodejs, including (thanks to W3 Schools for the rundown):

Importing Modules

The Core

Nodejs requires a few critical components that allow it to provide its functionality. These objects are part of what separate Nodejs applications from vanilla Javascript code:

1. Global Objects
2. Timer Methods
3. Sockets and Streams
4. Utilities
5. Events

Global Objects

There are three primary global objects available in Nodejs. They are:

  1. global
  2. process
  3. Buffer

Each of these objects are in a Node application’s namespace, meaning a require statement is not required (bad pun intended).

Variables and required objects are accessible within the application’s namespace. This access is restricted to the variables within the application, meaning you are unable to change the value of variables in other other modules. This prevents accidental collisions when code from another module runs.

The process object provides access to the Node installation, the three methods of standard I/O (stdin, stderr, stdout), and application memory usage.

The Buffer object handles binary data. You can read any type of data through a buffer, including a file, input stream, or network connection. A Buffer object take up to two parameters:

Timers

Timers in Nodejs allow programmers to delay and schedule execution of functions. The timer module includes the functions:

Sockets and Streams

There are four major types of streamed connections in Nodejs:

  1. TCP - net module
  2. HTTP - http module
  3. UDP/Datagram Socket - dgram module
  4. Readline/Child_Process - readline, child_process modules

Using a TCP connection, we can recieve messages from client’s standard input on the server program. The process is used directly here to access standard I/O streams.

Working with I/O

The .pipe(<stream>) is used to send the ouput of one stream to another.

Reading streams with readline

The readline module allows the reading of standard I/O streams line by line during program execution. When the programmer is done reading a stream, they must be closed. The REPL is implemented by piping your terminal input stdin, executing Javascript commands and piping stdout back to your terminal.

Using system streams with child_process

Using the child_process module, a Node application can make system calls and recieve input from standard I/O. We do this in Node by defining a child process and redirecting its input and output by defining functions for whenever specific input is recieved.

For example, let’s take the command ls:

You can specify how the function interacts with I/O by using the .on() method

Specifying how ls() interacts with stdin, stdout, and stderr:

ls.stdout.on('data', (data) => {
  console.log(`The output of ls is ${data}`)
})

ls.stderr.on('data', (data) => {
  console.log(`ls exited with error ${data}`)
})

ls.on('close', (code) => {
  console.log(`child process exited with code ${code}`)
}

The program below illustrates an elaborate way to execute the command: ls | grep "fork"

Utilities

The utilities object enables inheritance in Node. An object can be inherited by another object using the inherits function:

util.inherits(<source-object>, <target-object>)

Events & EventEmitter

As mentioned previously, event based programming is fundamental to the Node philosophy. The events module allows programmers to define actions for events much like try/catch blocks in Java and C++ or try/except blocks in Python. This method of programming puts the programmer in an event driven mindset to focus on all the events that a program must handle. Node modules are written to minimize the amount of boilerplate code written and shift focus to the actions.

Here are the steps to define an event:

  1. require: require('events')
  2. instantiate
  3. define the callback
  4. define the event

JavaScript

Data Types

JavaScript has primitive data types, which are immutable

  1. Number
  2. String
  3. Boolean
  4. Null
  5. Undefined
  6. Symbol

JavaScript also has some built-in objects

  1. Array
  2. Date
  3. RegExp
  4. Map & WeakMap
  5. Set & WeakSet

Specifying Integer Type

Number Properties

Special Characters

Code Description
\n newline
\r carriage return
\t horizontal tab
\' single quote
\$ dollar sign
\\ back-slash
\b backspace
\f form feed
\v vertical tab
&grave; grave symbol

String Substitutions

null and undefined

Objects

UTF-8

A variable can be defined using normal letters, as well as UTF-8 characters

Arrow Functions

Arrow functions allow us to give a function an identifier.

// Create a function 'squareIt' accepting an input 'x' and returning 'x' squared
const squareIt = (x) => x * x

// After 'squareIt' has been written, we can now call the identifier and give it input
squareIt(10) // '100'

Equality ‘==’ vs. ‘===’

The identity operator === will compare both types and values between two variables. JavaScript objects are compared by reference, not by value. An object is equal to itself, but not equal to a different object with the same value.

There are also some edge cases worth noting:

JavaScript Arrays

The Mozilla Javascript Documentation for Arrays will explain it better than I can.

The “in” operator

The in operator evaluates to true if the left-side value is the name of a property of the right-side object. This results in some counterintuitive logic at times, an example is provided below:

// Arrays
let trees = ['redwood', 'bay', 'cedar', 'oak', 'maple']
0 in trees        // returns true (array index 0 exists)
3 in trees        // returns true (array index 3 exists)
6 in trees        // returns false (array index 6 does not exist)
'bay' in trees    // returns false (you must specify the index number, not the value at that index)
'length' in trees // returns true (length is an Array property)
Symbol.iterator in trees // returns true (arrays are iterable, works only in ES2015+)

// Predefined objects
'PI' in Math          // returns true

// Custom objects
let mycar = {make: 'Honda', model: 'Accord', year: 1998}
'make' in mycar  // returns true
'model' in mycar // returns true
const data = [7, 8, 9]
"0" in data // true: array has an element "0"
1 in data // true: numbers are converted into strings
7 in data // false: no 7th element in this array

GitHub Package Registry

Add the following two lines to your ~/.npmrc

//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
registry = https://npm.pkg.github.com

Add the read:packages and write:packages permissions to your GITHUB_TOKEN environment variable in the GitHub tokens page

Install a Package

To add this Package registered on the GitHub NPM Registry, enter the following command

npm install @codertocat/hello-world-npm

Alternatively, you can add the package as a dependency to the project’s package.json

{
  "name": "testjs",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "@codertocat/hello-world-npm": "^1.0.2"
  }
}

Publish a Package

Add the following to your package’s package.json

{
  "publishConfig": {
    "registry":"https://npm.pkg.github.com/"
  }
}

Files

Express

MongoDB