Table of Contents
_________________
1 Introduction
2 scope
3 refs
4 npm
.. 4.1 Initialize a project
.. 4.2 Installing
.. 4.3 Removing
.. 4.4 Other things
5 javascript core functionality (language explanation)
.. 5.1 closures
.. 5.2 hoisting
.. 5.3 lexical environment
.. 5.4 undefined and null
.. 5.5 operators
.. 5.6 destructuring
..... 5.6.1 Example 1
..... 5.6.2 Example 2
..... 5.6.3 Example 3
.. 5.7 comments
.. 5.8 object
..... 5.8.1 creating objects
..... 5.8.2 the syntax for accessing the property of an object
..... 5.8.3 adding New Properties
..... 5.8.4 deleting Properties
..... 5.8.5 prototype
..... 5.8.6 adding a Method to an Object
..... 5.8.7 JSON (JavaScript Object Notation)
..... 5.8.8 bind
.. 5.9 arrays
.. 5.10 strict mode
.. 5.11 typeof
.. 5.12 operators
..... 5.12.1 !== vs. !=
.. 5.13 let vs var
.. 5.14 const
.. 5.15 casting
.. 5.16 numeric
.. 5.17 strings
.. 5.18 regexps
..... 5.18.1 caret (^)
..... 5.18.2 extract substring
.. 5.19 require
.. 5.20 arrow functions
.. 5.21 iterators
.. 5.22 generators
..... 5.22.1 Example 1
..... 5.22.2 Example 2
.. 5.23 template literals
.. 5.24 multi-line strings
.. 5.25 implicit returns in arrow functions
.. 5.26 key/property shorthand
.. 5.27 method definition shorthand
.. 5.28 classes
..... 5.28.1 static functions
..... 5.28.2 private
..... 5.28.3 Example 1
..... 5.28.4 Example 2 (inheritance)
..... 5.28.5 Example 3 (getters and setters)
.. 5.29 the ternary operator
.. 5.30 loops
.. 5.31 errors
.. 5.32 base 10 to binary
.. 5.33 chain assignments
.. 5.34 || operator
.. 5.35 loops
.. 5.36 default function parameters
6 general computer science
.. 6.1 little and big endian
7 language shell (REPL)
.. 7.1 misc
8 [Node] Misc.
.. 8.1 running as an executable
.. 8.2 Ensure paths are joined correctly on Linux/Windows
.. 8.3 global
.. 8.4 console
.. 8.5 a simple object
.. 8.6 a http client
.. 8.7 a https client
.. 8.8 a web server
.. 8.9 printing the user agent
.. 8.10 parse an url with parameters
.. 8.11 receiving data
.. 8.12 dates
.. 8.13 avoiding nested callbacks
.. 8.14 good packages to know about
.. 8.15 assertions
.. 8.16 Math
.. 8.17 linting
9 Buffers
.. 9.1 Data URIs
10 Streams
.. 10.1 Pipe
.. 10.2 pipeline - automatic cleaning of streams
.. 10.3 Transform stream
.. 10.4 Other functions
.. 10.5 Example 1
.. 10.6 Example 2
.. 10.7 Example 3
.. 10.8 A duplex stream
.. 10.9 A webserver 1
.. 10.10 A webserver 2
.. 10.11 inherit from a base object
.. 10.12 fs.createReadStream
.. 10.13 read a file into a buffer
.. 10.14 errors
.. 10.15 a duplex stream (PassThrough)
11 Timers
.. 11.1 Examples
..... 11.1.1 Example 1
..... 11.1.2 Example 2
12 events (EventEmitter)
.. 12.1 Example 1 - inheriting from EventEmitter
.. 12.2 Example 2 - adding a listener
.. 12.3 Example 3 - using domains to encapsulate errors from several classes
.. 12.4 process.nextTick
.. 12.5 Example 4 - simple
13 Module system
.. 13.1 Examples
.. 13.2 __dirname and __filename
.. 13.3 Example 1
.. 13.4 Example 2
.. 13.5 Example 3 - a more extensive module
.. 13.6 To publish a module
.. 13.7 Example 4
..... 13.7.1 The module
..... 13.7.2 the loader
14 File System
.. 14.1 Example 1 - Reading input from stdin
.. 14.2 Example 2 - Opening a file
.. 14.3 Example 3 - Reading a directory
.. 14.4 Example 4 - Reading directory content inside a http server
.. 14.5 Example 5 - Filtering directory content to only directories
.. 14.6 Example 6 - Get file size in bytes
.. 14.7 Example 7 - Read a fill using fs.readFile (useful if there is encoding)
.. 14.8 Example 8 - Check file permissions
15 Diagnostics
.. 15.1 Logging
.. 15.2 Measuring time
.. 15.3 debug
.. 15.4 inspect
16 Operating system
.. 16.1 process
..... 16.1.1 uncaughtException
..... 16.1.2 Add a POSIX signal listener
.. 16.2 require('os')
17 child processes
.. 17.1 spawn: runs the program asynchronously, without blocking the event loop
..... 17.1.1 Detachment
..... 17.1.2 unref
.. 17.2 exec: runs the program in a shell
.. 17.3 execFile: runs the program without a shell
.. 17.4 fork
.. 17.5 execSync
18 unit testing
.. 18.1 describe("title", function() { ... })
.. 18.2 it("use case description", function() { ... })
.. 18.3 assert.equal(value1, value2)
.. 18.4 Example 1
..... 18.4.1 project/test/blaha.js
..... 18.4.2 project/index.js
..... 18.4.3 project/package.json
..... 18.4.4 final
.. 18.5 Example 2
.. 18.6 Example 3
.. 18.7 Asynchronous Code
..... 18.7.1 Using async functions
..... 18.7.2 Legacy approach
.. 18.8 Synchronous Code
19 Control flow
.. 19.1 async.series
..... 19.1.1 Example 1
..... 19.1.2 Example 2
..... 19.1.3 Example 3
.. 19.2 async.parallel
..... 19.2.1 Example 1
..... 19.2.2 Example 2
.. 19.3 async.waterfall
20 Promises
.. 20.1 using "then"
..... 20.1.1 Example 1
..... 20.1.2 Example 2
.. 20.2 util.promisify
.. 20.3 examples
.. 20.4 alternative to promise.then
..... 20.4.1 async
..... 20.4.2 await
.. 20.5 errors
21 paths
22 perf_hooks (performance metrics)
.. 22.1 Example 1
.. 22.2 Example 2 -- timerify
23 querystring
24 readline
.. 24.1 Example 1
.. 24.2 Example 2 - Read one line at a time
25 fs (file system)
26 semantic versioning
27 package.json
.. 27.1 scripts
.. 27.2 dependency types
28 node executable
.. 28.1 command line flags
.. 28.2 exit codes
1 Introduction
==============
These are my study notes for the OpenJS Node.js Application Developer
(JSNAD) exam. I have compiled this document from a number of public
sources. I hope it can be useful for anyone else pursuing the JSNAD.
-- Oscar Franzén
/ May, July 2020
2 scope
=======
,----
| Buffer and Streams – 11%
| Node.js Buffer API’s
| Incremental Processing
| Transforming Data
| Connecting Streams
| Control flow – 12%
| Managing asynchronous operations
| Control flow abstractions
| Child Processes – 8%
| Spawning or Executing child processes
| Child process configuration
| Diagnostics – 6%
| Debugging Node.js
| Basic performance analysis
| Error Handling – 8%
| Common patterns
| Handling errors in various scenarios
| Node.js CLI – 4%
| Node executable command line flags
| Events – 11%
| The event system
| Building event emitters
| Consuming event emitters
| File System – 8%
| Input/output
| Watching
| JavaScript Prerequisites – 7%
| Language fundamentals
| Scoped to core language features introduced since EcmaScript 1 and still heavily used today
| Module system – 7%
| CommonJS Module System only
| Process/Operating System – 6%
| Controlling the process
| Getting system data
| Package.json – 6%
| Package configuration
| Dependency management
| Unit Testing – 6%
| Using assertions
| Testing synchronous code
| Testing asynchronous code
`----
3 refs
======
- Exam version of Node.js: v. 12 LTS
- Node.js 12.x.x Documentation,
[https://nodejs.org/dist/latest-v12.x/docs/api/]
- Node Cookbook, 3rd Edition, Chapters 1, 2, 3, 4 and 9
[https://github.com/PacktPublishing/Node-Cookbook-3rd-Ed]
- [https://nodeschool.io/]
- [https://javascript.info/promise-chaining#returning-promises]
4 npm
=====
Usually, modules will be installed locally in a folder named
node_modules, which can be found in your current working
directory. This is the directory require() will use to load modules in
order to make them available to you.
4.1 Initialize a project
~~~~~~~~~~~~~~~~~~~~~~~~
,----
| mkdir proj
| cd proj
| npm init
| # don't ask questions
| npm init -y
`----
4.2 Installing
~~~~~~~~~~~~~~
,----
| npm install
| npm install @
|
| # For the latest version
| npm install @latest
|
| # If you don’t know the exact version of the package, NPM allows using
| # semantic ranges to define the version. This command will install the
| # latest 4.x.x version
| npm install @^4.0.0
|
| npm install
| npm install
|
| # github
| npm install username/repository
`----
Automatically add the installed package to your package.json as a
dependency (useful if someone else installs your package, npm will
automatically read dependencies from the package.json file and install
the listed versions):
,----
| npm install --save
|
| # install a development dependency (they will end up in "devDependencies"
| # in package.json)
| npm install --save-dev
`----
Install package globally (/usr/local/lib/node_modules):
,----
| sudo npm install -g
|
| # install into a specific directory
| npm install --prefix=~/blaha/modules mymodule
|
| # The prefix setting stores the location for globally installed modules,
| # we can view this with:
| npm config set prefix
`----
4.3 Removing
~~~~~~~~~~~~
,----
| # these are aliases
| npm remove
| npm rm
| npm r
| npm uninstall
| npm unlink
|
| # update package.json as well
| npm remove --save
|
| # clean up your node_modules/ folder (i.e. remove dependencies that are not
| # needed)
| npm prune
`----
4.4 Other things
~~~~~~~~~~~~~~~~
,----
| npm search
|
| # set name
| npm config set init.author.name "Foo Bar"
|
| # To see a list of all modules that a project is currently using
| npm ls
| npm list
|
| # update a package to its latest version
| npm update
|
| # If you do not specify a package name, it updates all packages to their latest version
| npm update
|
| # increment version of your project
| # (cwd in the directory where the package.json is located)
| npm version major
| npm version minor
| npm version patch
|
| # check for outdated packages
| npm outdated
`----
5 javascript core functionality (language explanation)
======================================================
5.1 closures
~~~~~~~~~~~~
A closure is a function having access to the parent scope, even after
the parent function has closed.
A closure is a function which has access to the variable from another
function’s scope. This is accomplished by creating a function inside a
function. Of course, the outer function does not have access to the
inner scope.
Global variables can be made local (private) with closures.
*Important*: Variables created without a declaration keyword (var,
let, or const) are always global, even if they are created inside a
function.
,----
| function foobar(i) {
| var baz = i;
| var internalFoobar = function() {
| console.log(baz ++ );
| };
| return internalFoobar;
| }
|
| var myFoobar = foobar(1);
| myFoobar(); // 1
| myFoobar(); // 2
| myFoobar(); // 3
`----
5.2 hoisting
~~~~~~~~~~~~
Variable and function names can be used before declaring it. The
JavaScript compiler moves all the declarations of variables and
functions at the top so that there will not be any error. This is
called hoisting.
,----
| x = 1;
|
| alert('x = ' + x); // display x = 1
|
| var x;
`----
Hoisting is only possible with declaration but not the
initialization. JavaScript will not move variables that are declared
and initialized in a single line.
,----
| alert('x = ' + x); // display x = undefined
|
| // not hoisted
| var x = 1;
`----
Value of x will be undefined because var x = 1 is not hoisted. Please
note that JavaScript compiler does not move function expression.
5.3 lexical environment
~~~~~~~~~~~~~~~~~~~~~~~
Lexical Environment in JavaScript is created every time you create a
scope using the curly brackets {}. It can be nested: {{…}}.
5.4 undefined and null
~~~~~~~~~~~~~~~~~~~~~~
*A variable without a value, has the value undefined*. The type is
also undefined.
In JavaScript, the data type of null is an object.
,----
| typeof(undefined) // undefined
| typeof(null) // object
|
| null === undefined // false
| null == undefined // true
`----
5.5 operators
~~~~~~~~~~~~~
Operator Description
----------------------------------------
** Exponentiation
% Modulus (division remainder)
++ increment
-- decrement
5.6 destructuring
~~~~~~~~~~~~~~~~~
Shorthand for taking property from an object and loading into a
variable.
5.6.1 Example 1
---------------
,----
| const {test} = require('mymod');
|
| // same as:
|
| const test = require('mymod').test;
`----
5.6.2 Example 2
---------------
,----
| const product = { label: 'Yellow notebook',
| price: 4,
| stock: 200,
| salePrice: undefined,
| rating: -1};
|
| const myFunc = function(type, { label, stock }) {
| console.log(type, label, stock);
| }
|
| myFunc('order', product);
`----
5.6.3 Example 3
---------------
,----
| var obj = { a: 1, b: 2, c: 3 };
|
| var a = obj.a;
| var b = obj.b;
| var c = obj.c;
|
| // equivalent
| let {a, b, c} = obj;
`----
5.7 comments
~~~~~~~~~~~~
,----
| // comment
|
| /*
| * Another comment
| */
`----
5.8 object
~~~~~~~~~~
JavaScript objects are containers for named values, called properties
and methods. In JavaScript, almost everything is an object.
*Every JavaScript function is actually a Function object*
- Booleans can be objects (if defined with the new keyword)
- Numbers can be objects (if defined with the new keyword)
- Strings can be objects (if defined with the new keyword)
- Dates are always objects
- Maths are always objects
- Regular expressions are always objects
- Arrays are always objects
- Functions are always objects
- Objects are always objects
5.8.1 creating objects
----------------------
§ 5.8.1.1 Example 1
,----
| // These two are equivalent
| var obj = new Object();
| var obj = {};
`----
§ 5.8.1.2 Example 2
,----
| var person = { firstName: "Foo",
| lastName: "Bar",
| age: 42,
| eyeColor: "pink"
| };
|
| // equivalent
| var person = new Object();
| person.firstName = "Foo";
| person.lastName = "Bar";
| person.age = 42;
| person.eyeColor = "pink";
`----
§ 5.8.1.3 Example 3 - creating an object using a constructor function
Constructors do not have a return statement; their task is to write
all necessary stuff into `this', and it automatically becomes the
result.
There are two conventions:
- They are named with capital letter first
- They should be executed only with "new" operator
,----
| // the function that declares the object serves as its constructor
| function Test() {
| this.X = 0;
| this.Y = 0;
|
| this.move = function(x, y) {
| this.X = x;
| this.Y = y;
| };
| }
|
| var foo = new Test();
`----
5.8.2 the syntax for accessing the property of an object
--------------------------------------------------------
,----
| objectName.property // person.age
| objectName["property"] // person["age"]
|
| // the expression must evaluate to a property name.
| objectName[expression] // x = "age"; person[x]
`----
5.8.3 adding New Properties
---------------------------
,----
| // assuming the object already exists, you can then give it new
| // properties:
| person.planet = "Magrathea";
`----
5.8.4 deleting Properties
-------------------------
,----
| var person = {firstName: "Foo", lastName: "Bar", age: 42, eyeColor: "pink"};
| delete(person.age); // eqv: delete(person["age"]);
`----
5.8.5 prototype
---------------
typeof(Object); // function
It has prototype property with useful methods like toString, valueOf,
etc.
Every object instance on creation receives __proto__ property.
An object's __proto__ and Object.prototype is exactly the same object.
§ 5.8.5.1 Example 1 -- adding properties to all instances of an object
JavaScript objects inherit the properties of their prototype. By
default, JavaScript engine provides the Object() function and an
anonymous object that can be referenced via the Object.prototype.
In JavaScript, functions are objects. You can work with functions as
if they were objects.
The prototype is an object that is associated with every functions and
objects by default in JavaScript, where function's prototype property
is accessible and modifiable and object's prototype property (aka
attribute) is not visible.
,----
| function Student() {
| this.name = 'Foo';
| this.gender = 'Unknown';
| }
|
| var studObj1 = new Student();
| studObj1.age = 42;
| alert(studObj1.age); //
|
| var studObj2 = new Student();
| alert(studObj2.age); // undefined
`----
As you can see in the above example, age property is attached to
studObj1 instance. However, studObj2 instance will not have age
property because it is defined only on studObj1 instance.
Prototypes can be used to add properties at later stage to a function
which will be shared across all the instances.
,----
| function Student() {
| this.name = 'John';
| this.gender = 'M';
| }
|
| Student.prototype.age = 15;
|
| var studObj1 = new Student();
| alert(studObj1.age); // 15
|
| var studObj2 = new Student();
| alert(studObj2.age); // 15
`----
§ 5.8.5.2 Example 2 -- implementing inheritance
Doing it this way the object does not need to carry around the
functions in every new instance.
,----
| function Shape () {
|
| }
|
| Shape.prototype.X = 0;
| Shape.prototype.Y = 0;
| Shape.prototype.move = function (x, y) {
| this.X = x;
| this.Y = y;
| }
|
| Shape.prototype.distance_from_origin = function () {
| return Math.sqrt(this.X*this.X + this.Y*this.Y);
| }
|
|
| Shape.prototype.area = function () {
| throw new Error("I don't have a form yet");
| }
|
| var s = new Shape();
|
| s.move(10, 10);
| console.log(s.distance_from_origin());
`----
It can now be extended again:
,----
| function Square() {
| }
|
| Square.prototype = new Shape();
| Square.prototype.Width = 0;
|
| Square.prototype.area = function () {
| return this.Width * this.Width;
| }
| var sq = new Square();
|
| sq.move(-5, -5);
| sq.Width = 5;
|
| console.log(sq.area());
| console.log(sq.distance_from_origin());
`----
§ 5.8.5.3 Example 3 -- using Object.create
Object.create(proto, [propertiesObject]) ^The object which should be
the prototype of the newly created object.
,----
| const test = {
| isHuman: false,
| printIntroduction: function() {
| console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
| }
| };
|
| const me = Object.create(test);
`----
§ 5.8.5.4 Example 4
,----
| const wolf = {
| howl: function() {
| console.log(this.name + ': awoooooooo');
| }
| };
|
| const dog = Object.create(wolf, {
| woof: {
| value: function() {
| console.log(this.name + ': woof')
| }
| }
| });
|
| function createDog (name) {
| return Object.create(dog, {
| name: {value: name + ' the dog'}
| })
| }
|
| const rufus = createDog('Rufus');
|
| rufus.woof(); // prints "Rufus the dog: woof"
| rufus.howl(); // prints "Rufus the dog: awoooooooo"
|
| console.log(Object.getPrototypeOf(rufus) === dog) //true
| console.log(Object.getPrototypeOf(dog) === wolf) //true
`----
5.8.6 adding a Method to an Object
----------------------------------
,----
| person.name = function() {
| return this.firstName + " " + this.lastName;
| };
`----
5.8.7 JSON (JavaScript Object Notation)
---------------------------------------
§ 5.8.7.1 JSON.parse
Takes a JSON string and converts it to an object.
§ 5.8.7.2 JSON.stringify
Takes an object an converts it to a string.
,----
| var p = { name: "Foo",
| age: 42,
| city: "Foobar City"
| };
|
| var str = JSON.stringify(p);
`----
5.8.8 bind
----------
,----
| const module = {
| x: 42,
| getX: function() {
| return this.x;
| }
| };
|
| const unboundGetX = module.getX;
| console.log(unboundGetX()); // The function gets invoked at the global scope
| // b/c getX is no longer a part of module
| // expected output: undefined
|
| const boundGetX = unboundGetX.bind(module);
|
| console.log(boundGetX());
| // expected output: 42
`----
5.9 arrays
~~~~~~~~~~
arrays are objects.
,----
| var arr = new array();
| // or
| var arr = [];
|
| // V8 has a language extension to let you test determinatively whether or
| // not something is an array
| arr.isArray();
|
| // to add an item to the end of an array
| arr.push('test');
|
| // remove last item
| arr.pop();
|
| arr.join(', ');
|
| arr.sort();
|
| ['this', 'is', 'an', 'array'].forEach(function(x) {
| console.log(x);
| });
|
| var arr = [
| { num: 42, name: 'test'},
| { num: -1, name: 'foobar'}
| ];
|
| arr.find(function(i) {
| return i.num === 42;
| });
`----
,----
| function myFilter(value) {
| return value > 42;
| }
|
| var numbers = [9, 16, 25, 1000, 41, 100, 32];
| var over42 = numbers.filter(myFilter);
`----
5.10 strict mode
~~~~~~~~~~~~~~~~
,----
| // to opt in for strict mode, add the following to the top of the script:
| "use strict";
`----
5.11 typeof
~~~~~~~~~~~
,----
| typeof(42); // number
| typeof('hello'); // string
| typeof(10n); // bigint
| typeof(Math); // object
`----
5.12 operators
~~~~~~~~~~~~~~
Operator Description
---------------------------------------------------------------------------------
Strict equal, `=' Returns true if the operands are equal and of the same type.
!== not equal or not equal type
5.12.1 !== vs. !=
-----------------
,----
| var q1 = 42;
| var q2 = '42';
|
| if (q1 !== q2) {
| console.log('hello');
| }
|
| if (q1 != q2) {
| console.log('hello');
| }
`----
5.13 let vs var
~~~~~~~~~~~~~~~
Main difference is scoping rules. Variables declared by var keyword
are scoped to the immediate function body (hence the function scope)
while let variables are scoped to the immediate enclosing block
denoted by { } (hence the block scope).
A variable defined using a var statement is known throughout the
function it is defined in, from the start of the function.
A variable defined using a let statement is only known in the block it
is defined in, from the moment it is defined onward.
The let keyword conceals that variable to its own scope. It provides
data privacy because sometimes you want to limit the use of a variable
to a scope.
The var keyword "hoists" the variable definition (its name) up to the
global scope. Regardless what block-scope your variable is defined in
using var, it always becomes available at the uppermost scope.
Variables defined inside function-scope are concealed to it —
regardless of whether you used var or let; this is also true of
callback functions.
,----
| function run() {
| var foo = "Foo";
| let bar = "Bar";
|
| console.log(foo, bar);
|
| if (true) {
| let baz = "Bazz";
| var baz2 = "Bazz2";
| console.log(baz);
| }
|
| console.log(baz2); // OK
| console.log(baz); // ReferenceError
| }
|
| run();
`----
5.14 const
~~~~~~~~~~
The `const' keyword makes the variable non-assignable (but it is not
immutable).
5.15 casting
~~~~~~~~~~~~
,----
| parseInt('42');
| parseFloat('42.42');
`----
,----
| var out = '42';
| console.log(typeof(out));
| console.log(typeof(+out));
|
| // same thing as:
| console.log(typeof(Number(out)));
`----
5.16 numeric
~~~~~~~~~~~~
,----
| isNaN(parseInt('test'));
| isFinite(10/0);
`----
5.17 strings
~~~~~~~~~~~~
,----
| var foobar = 'Zaphod Beeblebrox';
| // get length
| foobar.length;
|
| // find a string within another string
| foobar.indexOf(' Beeble'); // 6
|
| // substrings
| foobar.slice(1, 5); // apho
| foobar.substr(1, 5); // aphod
|
| foobar.split(' '); // [ 'Zaphod', 'Beeblebrox' ]
|
| // removes whitespaces from the beginning and end of a strring
| ' testing '.trim();
|
| str = "Please visit us in the next galaxy.";
| var n = str.replace(/galaxy/g, "episode");
|
| str.charAt(0);
`----
5.18 regexps
~~~~~~~~~~~~
,----
| var p = /test/;
|
| // search for "test" in "testing"
| p.test('testing');
|
| var p = /hej\S+/;
| p.test('hejsan');
|
| var p = /hej\S+/i; // case insensitive
`----
Modifier Meaning
------------------------------------------------------------------------
i case insensitive
g global
m treat the whole string as one line even if it has linebreaks
5.18.1 caret (^)
----------------
The caret serves two different purposes. It is a special character
that denotes "the beginning of a line" and it is a "not" operator
inside of []s. Matches any character that is not a vowel followed by
any number of characters. Matches a vowel at the start of a line,
followed by any number of char.
,----
| var str = 'hej 42 qwe';
| str.replace(/[^0-9]+/, ''); // '42 qwe'
`----
5.18.2 extract substring
------------------------
,----
| var str = 'hej 42 qwe';
| re = /^(\S+) /;
| str.match(re)
`----
5.19 require
~~~~~~~~~~~~
Looks for files with the .node file extension and initialize those as
dynamically-linked libraries. The .node extension can usually be
omitted.
5.20 arrow functions
~~~~~~~~~~~~~~~~~~~~
Syntactically compact alternative to a regular function expression.
,----
| var elements = [
| 'Hydrogen',
| 'Helium',
| 'Lithium',
| 'Beryllium'
| ];
|
| // This statement returns the array: [8, 6, 7, 9]
| elements.map(function(element) {
| return element.length;
| });
|
| // The regular function above can be written as the arrow function below
| elements.map((element) => {
| return element.length;
| }); // [8, 6, 7, 9]
|
| // When there is only one parameter, we can remove the surrounding parentheses
| elements.map(element => {
| return element.length;
| }); // [8, 6, 7, 9]
|
| // also valid
| elements.map(element => element.length); // [8, 6, 7, 9]
`----
5.21 iterators
~~~~~~~~~~~~~~
In JavaScript an iterator is an object which defines a sequence and
potentially a return value upon its termination.
Specifically, an iterator is any object which implements the Iterator
protocol by having a next() method that returns an object with two
properties:
+----------+--------------------------------------------------------------+
| Property |Description |
+----------+--------------------------------------------------------------+
| value |The next value in the iteration sequence. |
+----------+--------------------------------------------------------------+
| done |This is true if the last value in the sequence has already |
| |been consumed. If value is present alongside done, it is the |
| |iterator's return value. |
+----------+--------------------------------------------------------------+
An iterator object can be iterated explicitly by repeatedly calling
next().
5.22 generators
~~~~~~~~~~~~~~~
A generator is a function that can stop midway and then continue from
where it stopped. A generator is a function which returns an object on
which you can call next(). Every invocation of next() will return an
object like this:
,----
| {
| value: Any,
| done: true|false
| }
`----
The value property will contain the value. The done property is either
true or false. When the done becomes true, the generator stops and
won’t generate any more values.
When called, generator functions do not initially execute their
code. Instead, they return a generator object. A generator function
always returns a generator object. The generator object is an
iterator. So you can use it in for-of loops or other functions
accepting an iterable.
When a value is consumed by calling the generator's next method, the
Generator function executes until it encounters the yield keyword.
5.22.1 Example 1
----------------
,----
| // generator functions have a '*'
| function* myGen() {
| yield 42;
| yield 'hello';
|
| // a return sets the 'done' property to true
| return 101;
| }
|
| let gen = myGen();
| let one = gen.next();
| alert(JSON.stringify(one)); // {value: 1, done: false}
|
| let two = gen.next();
| alert(JSON.stringify(two)); // {value: 2, done: false}
|
| let three = gen.next();
| alert(JSON.stringify(three)); // {value: 3, done: true}
`----
Instead use a loop to run the generator:
,----
| for (const val of myGen()) {
| console.log(val);
| }
`----
5.22.2 Example 2
----------------
,----
| function *myGen() {
| console.log('This will be executed first.');
|
| yield 'Hello, ';
| console.log('I will be printed after the pause');
| yield 'World!';
| }
|
| const genObj = myGen();
| console.log(genObj.next().value);
| console.log(genObj.next().value);
| console.log(genObj.next().value);
|
| // This will be executed first.
| // Hello,
| // I will be printed after the pause
| // World!
| // undefined
`----
5.23 template literals
~~~~~~~~~~~~~~~~~~~~~~
,----
| let date = '2020-05-14';
| let str = `today is ${date}`;
|
| // same as writing
| let str = 'today is ' + date;
`----
5.24 multi-line strings
~~~~~~~~~~~~~~~~~~~~~~~
,----
| let str = `this is a
| multi-line
| string!!`;
`----
5.25 implicit returns in arrow functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| function myFunc(a, b) {
| return a + b;
| }
|
| // equivalent (i.e. no body block)
| let fun = (a, b) => a + b
`----
5.26 key/property shorthand
~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var planet1 = 'earth';
| var planet2 = 'mars';
| var planet3 = 'neptunus';
|
| let planets = {
| planet1 : planet1
| planet2 : planet2
| planet3 : planet3
| };
|
| // equivalent
| let planets = {
| planet1,
| planet2,
| planet3,
| };
`----
5.27 method definition shorthand
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var lib = {
| sum: function(a, b) { return a + b; },
| mult: function(a, b) { return a * b; }
| };
|
| console.log( lib.sum(2, 3) ); // 5
| console.log( lib.mult(2, 3) ); // 6
|
| // equivalent
| const lib = {
| sum(a, b) { return a + b; },
| mult(a, b) { return a * b; }
| };
|
| console.log( lib.sum(2, 3) ); // 5
| console.log( lib.mult(2, 3) ); // 6
`----
5.28 classes
~~~~~~~~~~~~
5.28.1 static functions
-----------------------
The static keyword defines a static method for a class. Static methods
aren't called on instances of the class. Instead, they're called on
the class itself. These are often utility functions, such as functions
to create or clone objects.
5.28.2 private
--------------
They can only be read or written within the class body. By defining
things which are not visible outside of the class, you ensure that
your classes' users can't depend on internals, which may change
version to version.
,----
| class Rectangle {
| #height = 0;
| #width;
|
| constructor(height, width) {
| this.#height = height;
| this.#width = width;
| }
| }
`----
5.28.3 Example 1
----------------
,----
| class testing {
| constructor(par1, par2) {
| this.par1 = par1;
| this.par2 = par2;
| }
|
| myfunc() {
| return "something";
| }
|
| static hello() {
| return "world";
| }
| }
|
| myobj = new testing("foo", "bar");
| myobj.myfunc();
| testing.hello();
`----
5.28.4 Example 2 (inheritance)
------------------------------
,----
| class newtest extends testing {
| constructor(par1, par2, par3) {
| // A constructor can use the super keyword to call the
| // constructor of the super class.
| super(par1, par2);
| this.par3 = par3;
| }
|
| blaha() {
| return "something";
| }
| }
`----
5.28.5 Example 3 (getters and setters)
--------------------------------------
,----
| class qq {
| constructor(par1, par2) {
| this.par1 = par1;
| this.par2 = par2;
| }
|
| get foo() {
| return this.par1;
| }
|
| set foo(x) {
| this.par1 = x;
| }
| }
|
| qwe = new qq('abc', 'xvc');
| console.log(qwe.foo);
`----
5.29 the ternary operator
~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var foo = true;
|
| var q = foo ? 'yes' : 'no';
`----
5.30 loops
~~~~~~~~~~
,----
| var foobar = {
| qwe: 42,
| test: 41,
| hej: 44
| };
|
| for (key in foobar) {
| }
`----
5.31 errors
~~~~~~~~~~~
This works in javascript but not with Node. try-catch is used to catch
the exceptions thrown from the synchronous code execution. Don't use
try-catch on async operations.
,----
| function test() {
| throw new Error('this is an error');
| }
|
| try {
| test();
| } catch(e) {
| console.log(e.message);
| }
| finally {
| // executed regardless of the try / catch result
| }
`----
Asynchronous functions in Node do not throw errors. Instead, error
codes for the previous function are included as parameters in callback
functions. The `err' argument contain success or failure information.
*If err is null, it means the operation was successful.* If err is an
*Error object, it means there was an error.* There is usually a code
*and a message field.
5.32 base 10 to binary
~~~~~~~~~~~~~~~~~~~~~~
,----
| // Two dots (..) are needed to call a method on a number, since the
| // first is parsed as a decimal point.
|
| 8..toString(2); // 1011
`----
5.33 chain assignments
~~~~~~~~~~~~~~~~~~~~~~
,----
| let a, b, c;
|
| a = b = c = 2 + 2;
|
| alert( a ); // 4
| alert( b ); // 4
| alert( c ); // 4
`----
5.34 || operator
~~~~~~~~~~~~~~~~
returns the first truthy value.
,----
| let height = 0;
|
| console.log(height || 100); // 100
`----
5.35 loops
~~~~~~~~~~
,----
| let i = 0;
| while (i < 3) { // shows 0, then 1, then 2
| console.log(i);
| i++;
| }
|
| let i = 0;
| do {
| console.log(i);
| i++;
| } while (i < 3);
|
| for (let i = 0; i < 3; i++) { // shows 0, then 1, then 2
| console.log(i);
| }
|
| // breaking the loop
| break;
|
| // continue to the next iteration
| continue;
|
| // it gives a more descriptive way to compare a value with multiple
| // variants
|
| let a = 2 + 2;
|
| switch (a) {
| case 3:
| console.log('Too small');
| break;
| case 4:
| console.log('Exactly!');
| break;
| case 5:
| console.log('Too large');
| break;
| default:
| console.log("I don't know such values");
| }
`----
5.36 default function parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| function test(name='foobar', age) {
| console.log(name);
| console.log(age);
| }
|
| test();
`----
6 general computer science
==========================
6.1 little and big endian
~~~~~~~~~~~~~~~~~~~~~~~~~
Little and big endian are two ways of storing multibyte data-types (
int, float, etc). In little endian machines, last byte of binary
representation of the multibyte data-type is stored first. On the
other hand, in big endian machines, first byte of binary
representation of the multibyte data-type is stored first.
Decimal: 20200514 Binary: 1 00110100 00111100 01000010
Integers are commonly stored using a word of memory, which is 4 bytes
or 32 bits, so integers from 0 up to 4,294,967,295 (232 - 1) can be
stored. Below are the integers 1 to 5 stored as four-byte values (each
row represents one integer).
,----
| 0 : 00000001 00000000 00000000 00000000 | 1
| 4 : 00000010 00000000 00000000 00000000 | 2
| 8 : 00000011 00000000 00000000 00000000 | 3
| 12 : 00000100 00000000 00000000 00000000 | 4
| 16 : 00000101 00000000 00000000 00000000 | 5
`----
This may look a little strange; within each byte (each block of eight
bits), the bits are written from right to left like we are used to in
normal decimal notation, but the bytes themselves are written left to
right! It turns out that the computer does not mind which order the
bytes are used (as long as we tell the computer what the order is) and
most software uses this left to right order for bytes.
7 language shell (REPL)
=======================
,----
| node
`----
+---------+-----------------------------------------------------------+
| Command | Description |
+---------+-----------------------------------------------------------+
| .break | If you get lost during a multiline entry, typing .break |
| | will start you over again. |
+---------+-----------------------------------------------------------+
| .clear | Resets the context object and clears any multiline |
| | expression. This command basically starts you over again. |
+---------+-----------------------------------------------------------+
| .editor | Enter editor mode |
+---------+-----------------------------------------------------------+
| .exit | Exit the repl |
+---------+-----------------------------------------------------------+
| .help | Print help |
+---------+-----------------------------------------------------------+
| .load | Load JS from a file into the REPL session |
+---------+-----------------------------------------------------------+
| .save | Save all executed commands in this REPL session to a file |
+---------+-----------------------------------------------------------+
7.1 misc
~~~~~~~~
,----
| var repl = require("repl");
|
| // To create a new REPL, we call the start method on the repl
| // object. The syntax for this method is
| repl.start([prompt], [stream], [eval], [useGlobal], [ignoreUndefined]);
`----
8 [Node] Misc.
==============
8.1 running as an executable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| #!/usr/bin/env node
|
| console.log('hello world');
`----
8.2 Ensure paths are joined correctly on Linux/Windows
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| path.join(__dirname, 'test', 'hello.html')
`----
8.3 global
~~~~~~~~~~
Anything attached to global is available anywhere in the Node
application.
,----
| global.fish = 'babel';
| console.log(global.fish);
`----
8.4 console
~~~~~~~~~~~
,----
| console.log(...);
|
| // !!! console.warn / console.error are aliases !!!
| console.warn(...); // prints to stderr
|
| // Define stdout and stderr log files.
| var fs = require('fs');
| const output = fs.createWriteStream(`${__dirname}/src/console/stdout.log`);
| const errorOutput = fs.createWriteStream(`${__dirname}/src/console/stderr.log`);
|
| // Instance Console class and include stdout and stderr preferences.
| const myCons = new console.Console({ stdout: output,
| stderr: errorOutput });
|
| myCons.log('hello world');
| myCons.log('hello %s', 'world');
| myCons.error(new Error('oopsie'));
|
| const name = 'Mr. Test';
| myCons.warn(`Danger ${name}! Danger!`);
|
| // Try to construct a table with the columns of the properties of
| // tabularData (or use properties) and rows of tabularData and log it.
| // Falls back to just logging the argument if it can’t be parsed as tabular.
| console.table([{ a: 1, b: 'Y' },
| { a: 'Z', b: 2 }]);
|
| // ┌─────────┬─────┬─────┐
| // │ (index) │ a │ b │
| // ├─────────┼─────┼─────┤
| // │ 0 │ 1 │ 'Y' │
| // │ 1 │ 'Z' │ 2 │
| // └─────────┴─────┴─────┘
`----
8.5 a simple object
~~~~~~~~~~~~~~~~~~~
,----
| var fs = require('fs');
|
| // initializer for the object
| function Test() {
| this.file = 'hej.txt';
| this.check = function(cb) {
| fs.open(this.file, 'r', function(err, fh) {
| if (err) {
| cb(err);
| } else {
| fs.close(fh, function() {});
| cb(null);
| }
| });
| }
| }
|
| var qq = new Test();
| //qq.file = 'testing.txt';
| qq.check(function (err) {
| if (err) {
| console.log('cannot open file: ' + JSON.stringify(err));
| } else {
| console.log('opened file');
| }
| });
`----
8.6 a http client
~~~~~~~~~~~~~~~~~
,----
| var http = require('http');
| var options = {
| hostname: '127.0.0.1',
| port: 80,
| path: '/',
| method: 'GET'
| };
| var req = http.request(options, function(res) {
| console.log('STATUS: ' + res.statusCode);
| console.log('HEADERS: ' + JSON.stringify(res.headers));
| res.setEncoding('utf8');
| res.on('data', function (chunk) {
| console.log('Response: ' + chunk);
| });
| res.on('end', function (chunk) {
| console.log('Response ENDED');
| });
| });
| req.on('error', function(e) {
| console.log('problem with request: ' + e.message);
| });
| req.end();
`----
8.7 a https client
~~~~~~~~~~~~~~~~~~
,----
| const https = require('https');
| const url ='https://panglaodb.se';
| const request = https.request(url, function(response) {
| let data = '';
| response.on('data', function(chunk) {
| data = data +chunk.toString()
| });
|
| response.on('end', function() {
| const body = JSON.parse(data);
| console.log(body);
| });
| });
|
| request.on('error', function(err) {
| console.log('An error',err);
| });
|
| request.end();
`----
8.8 a web server
~~~~~~~~~~~~~~~~
,----
| var http = require('http');
|
| function qwe(req, res) {
| // When headers have been set with response.setHeader(), they will
| // be merged with any headers passed to response.writeHead(), with
| // the headers passed to response.writeHead() given precedence.
| res.writeHead(200, {"Content-Type" : "plain/text"});
| res.write('Hello world!\n');
| res.end();
|
| // alternative
| //res.writeHead(200, {"Content-Type" : "plain/text"});
| //res.end(JSON.stringify('OK');
| }
|
| http.createServer(qwe).listen(8080);
`----
8.9 printing the user agent
~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var http = require('http');
|
| http.createServer(function(req, res) {
| console.log(req.headers['user-agent']);
|
| // check and run different functions
| console.log(req.url);
| }).listen(8080);
|
`----
8.10 parse an url with parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var http = require('http');
| var url = require('url');
|
| http.createServer(function(req, res) {
| // second parameter must be set to true
| console.log(url.parse(req.url, true));
| }).listen(8080);
`----
8.11 receiving data
~~~~~~~~~~~~~~~~~~~
,----
| curl -X POST -H "Content-Type: application/json" -d "{'test' : 42}" 127.0.0.1:8080
`----
,----
| var http = require('http');
| var url = require('url');
|
| http.createServer(function(req, res) {
| req.on('readable', function() {
| var d = req.read();
|
| if (d) {
| console.log(d.toString());
|
| res.writeHead(200, 'Content-Type/text');
| res.end('OK');
| }
| });
|
| req.on('end', function() {
| console.log('no more data');
| });
| }).listen(8080);
`----
8.12 dates
~~~~~~~~~~
,----
| var d = new Date();
| console.log(d.toTimeString());
| // type "d." then [TAB] to see the other options, for example:
`----
8.13 avoiding nested callbacks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use functions!
,----
| var http = require('http');
|
| http.createServer(runner).listen(8080);
|
| function runner(req, res) {
| // do something
| if (err) return; // also part of reducing bracketing
| }
`----
8.14 good packages to know about
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+---------+----------------------------------------------------------------+
| Package |Description |
+---------+----------------------------------------------------------------+
| nodemon |No need to rerun "node app.js" everytime the source code files |
| |changes. Just do "nodemon app.js". |
+---------+----------------------------------------------------------------+
| yargs |Complex command line input. |
+---------+----------------------------------------------------------------+
| request |Fire off http requests. |
+---------+----------------------------------------------------------------+
| mocha |Unit testing. |
+---------+----------------------------------------------------------------+
|standard |For linting. |
+---------+----------------------------------------------------------------+
8.15 assertions
~~~~~~~~~~~~~~~
,----
| var assert = require('assert');
| assert(50 > 70);
|
| function add (a, b) {
| return a + b;
| }
|
| var expected = add(1,2);
| assert(expected === 3, 'one plus two is three');
|
| // these three assertions are equivalent:
| assert(expected == 3, 'one plus two is three');
| assert.ok(expected == 3, 'one plus two is three');
| assert.equal(expected, 3, 'one plus two is three');
`----
Function Description
--------------------------------------------------------------------------
equal Checks if two values are equal, using the equal operator (==)
deepEqual Checks if two objects or child objects are equal
assert Checks if a value is true. Same as assert.ok()
,----
| var assert = require('assert');
|
| var x = { a : { n: 0 } };
| var y = { a : { n: 0 } };
| var z = { a : { n: 1 } };
|
| assert.deepEqual(x, y); // OK
| assert.deepEqual(x, z); /*AssertionError: { a: { n: 0 } } deepEqual {a: { n: 1 } }*/
`----
8.16 Math
~~~~~~~~~
,----
| Math.random();
`----
8.17 linting
~~~~~~~~~~~~
,----
| # the linter is called "standard"
| npm install standard
| ./node_modules/bin/standard
`----
or add it as a run script in package.json:
,----
| "scripts": {
| "test": "echo \"Error: no test specified\" && exit 1",
| "lint": "standard"
| },
`----
Then it's just to type:
,----
| npm run lint
`----
9 Buffers
=========
,----
| var foo = 'bar';
| Buffer.isBuffer(foo); // false
|
| // new Buffer() is deprecated "due to security and usability issues".
| // Buffer.alloc, Buffer.allocUnsafe, or Buffer.from should be used instead
| // allocate 255 bytes
| var buf = new Buffer(255);
| // create a Buffer using string data
| var buf = new Buffer("hello world");
| // if incoming data has a different encoding than UTF-8
| var buf = new Buffer("SGVsbG8gd29ybGQK", "base64");
|
| // the underlying memory for Buffer instances created in this way is not
| // initialized. The contents of the newly created Buffer are unknown and may
| // contain sensitive data. Use Buffer.alloc() instead to initialize Buffer
| // instances with zeroes.
| var buf = Buffer.allocUnsafe(255);
|
| // it's better to use alloc b/c buffer is also initialized
| var buf = Buffer.alloc(255);
|
| // length is 255 and all values are 1
| var buf = Buffer.alloc(255, 1);
|
| // an encoding can also be specified
| var buf = Buffer.alloc(5, 8, 'utf8');
|
| // or the second safe method is creating a buffer from a string
| var buf = Buffer.from('hello world');
|
| cosole.log(Buffer.byteLength(buf));
|
| // check if node supports a certain character encoding
| Buffer.isEncoding('base64');
| Buffer.isEncoding('utf8');
|
| // can be used to compare buffers
| buf.compare(anotherBuf); // 0 if the same
| buf.equals(buf); // true if bytes are the same
|
| // check if a buffer includes another buffer
| buf.includes(buf2); // true if true
|
| // concatenate buffers
| var newBuf = Buffer.concat([buf1, buf2, buf3, ...]);
|
| // check index of another buf
| buf.indexOf(buf2);
|
| // identical to buf.indexOf(), except the last occurrence of value is
| // found rather than the first occurrence.
| buf.lastIndexOf(buf2);
|
| const buf = Buffer.from('buffer');
|
| // JSON representations of buffers
| JSON.stringify(buf); // returns a string
| buf.toJSON(); // returns an object
|
| // iterate through indices of a buffer (they call it "keys")
| for (const key of buf.keys()) {
| console.log(key);
| }
|
| // write an integer (42) to the first byte
| buf[0] = 42;
`----
,----
| var fs = require('fs');
|
| fs.readFile('test.txt', function(err, buf) {
| Buffer.isBuffer(buf); // true
| });
|
| fs.readFile('test.txt', function(err, buf) {
| console.log(buf.toString()); // default is UTF-8
| console.log(buf.toString('ascii'));
| });
|
| fs.readFile('binary.data', function(err, buf) {
| buf.readUInt32LE(4);
| // ^Number of bytes to skip before starting to read 32 bits
| });
|
| // slice a buffer
| var buf = Buffer.from("hello world");
| buf.slice(1,5).toString();
|
| // copy buf into newbuffer
| var newbuffer = Buffer.alloc(10);
| buf.copy(newbuffer, 0, 0, 5);
|
| // copy 20 bytes from 'buf' into a new buffer 'b'
| var b = Buffer.alloc(20);
| buf.slice(40,60).copy(b)
|
| // string length vs. byte length
| var str = 'foo';
| var buf = Buffer.alloc(1000);
| buf.write(str);
|
| // some characters in unicode need multiple bytes for encoding
| // (chinese characters are encoded by 3 bytes, but ASCII just needs 1 byte
| // per character)
| Buffer.byteLength(str);
|
| // concatenating buffers
| var b1 = Buffer.from("My name is ");
| var b2 = Buffer.from("foobar");
| var b3 = Buffer.concat([b1, b2]);
| console.log(b3.toString('utf8'));
`----
9.1 Data URIs
~~~~~~~~~~~~~
- [https://en.wikipedia.org/wiki/Data_URI_scheme]
- Provides a way to include data in-line in Web pages as if they were
external resources.
- A data URI consists of:
,----
| data:[][;base64],
`----
- An HTML fragment embedding a picture of a small red dot:
,----
|
`----
,----
| // read data and encode it to base64
| var data = fs.readFileSync('icon.png').toString('base64');
`----
10 Streams
==========
Streams are collections of data just like arrays or strings. The
difference is that streams might not be available all at once, and
they don't have to fit in memory. Just like we can compose commands by
piping other commands in a shell. Many of the built-in modules in Node
implement the streaming interface.
There are four fundamental stream types in the stream module:
Readable, Writable, Duplex, and Transform.
*Important*: The recommended way to use streams is via the `pipe', not
by using events. The `pipe' is used to connect streams together.
+-------------+---------------------------------------------+----------------+
| Base class | Description | Events |
+-------------+---------------------------------------------+----------------+
| Readable | Created with fs.createReadStream. | data, readable |
| | | end, error |
+-------------+---------------------------------------------+----------------+
| Writeable | Created with fs.createWriteStream | drain, finish, |
| | | error |
+-------------+---------------------------------------------+----------------+
| Duplex | Both readable and writetable (e.g. TCP | |
| | socket) | |
+-------------+---------------------------------------------+----------------+
| Transform | Can be used to modify or transform the data | |
| | as it is read and then written. | |
+-------------+---------------------------------------------+----------------+
10.1 Pipe
~~~~~~~~~
Readable streams can be "piped" (connected), to writable streams. This
makes data flow from the source stream to the destination stream
without much effort.
,----
| readableSrc.pipe(writableDest)
|
| // if were piping into a duplex stream, we can chain pipe
| // calls just like we do in a shell
| readableSrc.pipe(transformStream1).pipe(transformStream2).pipe(finalWrititableDest)
`----
10.2 pipeline - automatic cleaning of streams
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| // "pipeline" is a special function that takes multiple streams and
| // handles errors. A module method to pipe between streams forwarding
| // errors and properly cleaning up and provides a callback when the
| // pipeline is completed.
|
| // When using the basic pipe method, you are responsible for
| // destroying streams yourself when things go wrong, so one of the
| // main reasons to use pipeline as opposed to pipe is to make sure
| // streams are automatically cleaned up when errors occur.
|
| var pipeline = require('stream').pipeline;
|
| pipeline(stream1, stream2, stream3, function(err) {
| if (err) {
| console.error('Pipeline failed.', err);
| } else {
| console.log('Pipeline succeeded.');
| }
| });
`----
10.3 Transform stream
~~~~~~~~~~~~~~~~~~~~~
,----
| const { Transform, pipeline } = require('stream');
|
| var qq = new Transform({
| transform: function (chunk, encoding, callback) {
| callback(null, chunk.toString().toUpperCase());
| }
| });
|
| pipeline(process.stdin, qq, process.stdout, function(err) {
| console.log(err);
| });
`----
10.4 Other functions
~~~~~~~~~~~~~~~~~~~~
,----
| var fs = require('fs');
|
| var out_stream = fs.createWriteStream('output.txt');
| var out_stream2 = fs.createWriteStream('blaha.txt', { flags: 'a' });
|
| out_stream2.on('error', function(err) {
| // handle errors
| });
|
| var in_stream = fs.createReadStream('input.txt');
|
| in_stream.pipe(out_stream);
`----
10.5 Example 1
~~~~~~~~~~~~~~
,----
| var fs = require('fs');
| var foo;
|
| var rs = fs.createReadStream('/home/rand/Apps/R-3.5.3/README');
|
| rs.on('readable', function() {
| var d = rs.read();
|
| if (d) {
| foo += d.toString();
| }
| });
|
| rs.on('end', function() {
| console.log(foo);
| });
|
| rs.on('open', () => {
| console.log('Event: open');
| });
|
| rs.on('ready', () => {
| console.log('Event: ready');
| });
|
| rs.on('finish', () => {
| console.log('Event: finish');
| });
|
| rs.on('close', () => {
| console.log('Event: close');
| });
|
| /* Others */
| rs.on('error', () => {
| console.log('Event: error');
| });
|
`----
10.6 Example 2
~~~~~~~~~~~~~~
data.txt file will be written to clients one chunk at a time
immediately as they are received from the disk.
,----
| var fs = require('fs');
| var http = require('http');
|
| var server = http.createServer(function (req, res) {
| var stream = fs.createReadStream('data.txt');
| stream.pipe(res);
| }).listen(8080);
`----
10.7 Example 3
~~~~~~~~~~~~~~
,----
| var fs = require('fs');
| var http = require('http');
|
| var server = http.createServer(function (req, res) {
| var stream = fs.createReadStream('image.png');
| res.writeHead(200, {"Content-Type" : "image/png"});
| stream.pipe(res);
| });
`----
10.8 A duplex stream
~~~~~~~~~~~~~~~~~~~~
,----
| var zlib = require('zlib');
| var fs = require('fs');
|
| fs.createReadStream('style.css')
| .pipe(zlib.createGzip()) // createGzip() returns a duplex stream
| .pipe(fs.createWriteStream('style.css.gz');
`----
10.9 A webserver 1
~~~~~~~~~~~~~~~~~~
,----
| var http = require('http');
| var fs = require('fs');
| var zlib = require('zlib');
|
| http.createServer(function(req, res) {
| res.writeHead(200, { 'content-encoding': 'gzip' });
| fs.createReadStream(__dirname + '/index.html')
| .pipe(zlib.createGzip())
| .pipe(res);
| }).listen(8000);
`----
10.10 A webserver 2
~~~~~~~~~~~~~~~~~~~
Here `.pipe()' takes care of listening for 'data' and 'end' events
from the fs.createReadStream(). The file will be written to clients
one chunk at a time immediately as they are received from the disk.
,----
| var http = require('http');
| var fs = require('fs');
|
| http.createServer(function(req, res) {
| fs.createReadStream(__dirname + '/large_file.zip').pipe(res);
| }).listen(8000);
`----
10.11 inherit from a base object
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var Readable = require('stream').Readable;
| var util = require('util');
|
| function qwe() {
| Readable.call(this);
| }
|
| util.inherits(qwe, Readable);
`----
10.12 fs.createReadStream
~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var fs = require('fs');
| var rs = fs.createReadStream('blaha.txt', { encoding: 'utf8',
| highWaterMark: 16*1024 // buffering size
| });
| var ws = fs.createWriteStream('out.txt');
| rs.pipe(ws);
`----
10.13 read a file into a buffer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var fs = require('fs');
| var chunks = [];
| var buf;
| var rs = fs.createReadStream('text.txt');
|
| rs.once('error', function(err) {
| console.error(err);
| });
|
| rs.on('data', (chunk) => {
| chunks.push(chunk);
| });
|
| rs.once('end', function() {
| buf = Buffer.concat(chunks);
| });
`----
10.14 errors
~~~~~~~~~~~~
,----
| var readable = fs.createReadStream('file3.txt');
| var writable = fs.createWriteStream('file4.txt');
|
| readable.on('error', console.error);
| writable.on('error', console.error);
|
| readable.pipe(writable);
`----
10.15 a duplex stream (PassThrough)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var { PassThrough } = require('stream');
|
| var pt = new PassThrough();
|
| process.stdin.pipe(pt).pipe(process.stdout);
`----
11 Timers
=========
*Important*: Timers are not necessarily accurate if there are
long-running blocking tasks.
+-----------------+--------------------------------------------------------+
| Fuction |Description |
+-----------------+--------------------------------------------------------+
| setTimeout |Run a callback after a delay (in milliseconds). It will |
| |only be run once. setTimeout(callback, delay); |
+-----------------+--------------------------------------------------------+
| setInterval |Schedule the repeated execution of callback every delay |
| |milliseconds |
+-----------------+--------------------------------------------------------+
| clearTimeout |Prevents a timeout from triggering |
+-----------------+--------------------------------------------------------+
| clearInterval |Stops an interval from triggering. |
+-----------------+--------------------------------------------------------+
| setImmediate |A special timer that runs in a separate phase of the |
| |event loop. It uses a libuv API that schedules callbacks|
| |to execute after the poll phase has completed. Use |
| |setImmediate if you want to queue the function behind |
| |whatever I/O event callbacks that are already in the |
| |event queue. So in a case where you're trying to break |
| |up a long running, CPU-bound job using recursion, you |
| |would now want to use setImmediate rather than |
| |process.nextTick to queue the next iteration as |
| |otherwise any I/O event callbacks wouldn't get the |
| |chance to run between iterations. |
+-----------------+--------------------------------------------------------+
| process.nextTick|Use process.nextTick to effectively queue the function |
| |at the head of the event queue so that it executes |
| |immediately after the current function completes. Once |
| |the current turn of the event loop turn runs to |
| |completion, all callbacks currently in the next tick |
| |queue will be called. |
+-----------------+--------------------------------------------------------+
11.1 Examples
~~~~~~~~~~~~~
11.1.1 Example 1
----------------
,----
| var id = setTimeout(function() {
| console.log('foo');
| }, 1000);
|
| setInterval(function() {
| console.log('bar');
| }, 1000);
|
| clearTimeout(id);
`----
11.1.2 Example 2
----------------
,----
| var EventEmitter = require('events').EventEmitter;
|
| const ee = new EventEmitter();
|
| ee.on('event', function() {
| console.log('event 1 occurred');
| for (let i = 0; i < 10; i += 1) {
| console.log(`event 1-${i} occurred`);
| }
|
| setTimeout(function() {
| console.log('event 2 occurred');
| }, 0);
|
| setImmediate(function() {
| console.log('event 3 occurred');
| });
|
| process.nextTick(function() {
| console.log('event 0 occurred');
| });
|
| console.log('event 4 occurred');
| });
|
| ee.emit('event');
`----
12 events (EventEmitter)
========================
event.EventEmitter is a class which is used to provide a consistent
interface for emitting (triggering) and binding callbacks to events.
When an EventEmitter instance experiences an error, the typical action
is to emit an error event. Error events are treated as a special case
in Node. If there is no listener for it, then the default action is to
print a stack trace and exit the program.
,----
| // send three event signals (the listeners will be called in the order
| // they were registered)
| myobj.emit('just', 'another', 'event');
|
| // make a listener to fire first, before all of the other listeners
| // that have already been added
| myobj.prependListener('just', function() { /* ... */ });
|
| // remove all of the listeners and start over,
| myobj.removeAllListeners();
|
| // listen to an event only once
| myobj.once('nameofevent', function() {})
|
| // get number of listeners
| myobj.listenerCount('nameofevent');
`----
12.1 Example 1 - inheriting from EventEmitter
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Important*: Usage of util.inherits() is discouraged. Use the ES6
class and extends keywords to get language level inheritance support.
,----
| var util = require('util');
| var events = require('events');
|
| function bla() {
| events.EventEmitter.call(this);
| }
|
| // the Node approach to inheritance
| util.inherits(bla, events);
`----
The proper way would be to write it as:
,----
| const EventEmitter = require('events');
|
| class MyEmitter extends EventEmitter {};
| const myEmitter = new MyEmitter();
|
| myEmitter.on('event', function() {
| console.log('an event occurred');
| });
|
| myEmitter.emit('event');
`----
12.2 Example 2 - adding a listener
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var util = require('util');
| var events = require('events');
|
| function bla() {
| events.EventEmitter.call(this);
| }
|
| // the Node approach to inheritance
| util.inherits(bla, events.EventEmitter);
|
| var foo = new bla();
|
| foo.on('talk', function() {
| console.log('talk event triggered');
| });
|
| // it is possible to have multiple listeners for the same event
| foo.on('talk', function() {
| console.log('talk event 2 triggered');
| });
|
| // trigger event
| foo.emit('talk');
|
| // Functions to remove listeners:
| // removeListener(name, function reference)
| // removeAllListeners
|
| // To make an event listener run only ONCE
| foo.once('talk', function() {
| console.log('talk event triggered');
| });
`----
12.3 Example 3 - using domains to encapsulate errors from several classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var util = require('util');
| var domain = require('domain');
| var events = require('events');
| var audioDomain = domain.create();
|
| function AudioDevice() {
| events.EventEmitter.call(this);
| this.on('play', this.play.bind(this));
| }
|
| util.inherits(AudioDevice, events.EventEmitter);
|
| AudioDevice.prototype.play = function() {
| this.emit('error', 'not implemented yet');
| };
|
| function MusicPlayer() {
| events.EventEmitter.call(this);
| this.audioDevice = new AudioDevice();
| this.on('play', this.play.bind(this));
| this.emit('error', 'No audio tracks are available');
| }
|
| util.inherits(MusicPlayer, events.EventEmitter);
|
| MusicPlayer.prototype.play = function() {
| this.audioDevice.emit('play');
| console.log('Now playing');
| };
|
| audioDomain.on('error', function(err) {
| console.log('audioDomain error:', err);
| });
|
| audioDomain.run(function() {
| var musicPlayer = new MusicPlayer();
| musicPlayer.play();
| });
`----
12.4 process.nextTick
~~~~~~~~~~~~~~~~~~~~~
When in Node JS, one iteration of the event loop is completed. This is
known as a tick. `process.nextTick()' taking a callback function which
is executed after completing the current iteration/tick of the event
loop.
In the example below `process.nextTick' ensures that `events.emit' is
not called when `complexOperations()' is called.
,----
| var EventEmitter = require('events').EventEmitter;
|
| function complexOperations() {
| var events = new EventEmitter();
|
| // the event will now be emitted when the listener is ready
| process.nextTick(function() {
| events.emit('success');
| });
|
| return events;
| }
|
| complexOperations().on('success', function() {
| console.log('success!');
| });
`----
`process.nextTick' is an approach to give up control of execution, and
then when there is a free moment, call the provided function.
12.5 Example 4 - simple
~~~~~~~~~~~~~~~~~~~~~~~
,----
| var events = require('events');
|
| function test() {
| }
|
| test.prototype = new events.EventEmitter();
| //test.prototype.__proto__ = events.EventsEmitter.prototype;
| test.prototype.url = null;
| test.prototype.run = function(path) {
| var self = this;
| this.emit('start', path);
| setTimeout(function() {
| self.emit('end', path);
| }, 2000);
| }
|
| var q = new test();
|
| q.on('start', function(path) {
| console.log('start: ' + path);
| });
|
| q.on('end', function(path) {
| console.log('end: ' + path);
| });
|
| q.run('www.google.com');
`----
13 Module system
================
Modules can be installed with npm and then loaded with
`require'. Modules can be used to split projects in multiple files.
In development, you may find that using require() on the same module
multiple times always returns the same module, even if you have made
changes to that file. This is because modules are cached the first
time they are loaded, and any subsequent module loads will load from
the cache.
To get around this issue, you will have to delete the entry in the
cache. Do note that this is not recommended in production because the
delete will only delete the reference to the loaded module, not the
loaded data itself. The module is not garbage collected, so improper
use of this feature could lead to leaking memory.
13.1 Examples
~~~~~~~~~~~~~
,----
| module.exports = function() {
| console.log('hello world');
| };
|
| exports.test = function() {
| console.log('hello world');
| };
|
| function test() {
| console.log('hello world');
| }
|
| module.exports = { test: test };
|
| module.exports = { test: function() {
| console.log('hello world');
| }};
`----
13.2 __dirname and __filename
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Only defined in scripts, not REPL*
13.3 Example 1
~~~~~~~~~~~~~~
Save in `test.js'
,----
| function MyClass() {
| }
|
| MyClass.prototype = {
| method: function() {
| return 'Hello';
| }
| };
|
| var myClass = new MyClass();
|
| module.exports = myClass;
`----
Save in file.js
,----
| // important: path must start with "./"
| var qq = require('./test');
| var test = new qq();
`----
One can also write:
,----
| module.exports.test = function(a, b) { return a+b; }
`----
13.4 Example 2
~~~~~~~~~~~~~~
,----
| function test() {
| this.qwerty = 42;
| }
|
| exports.hej = test;
`----
13.5 Example 3 - a more extensive module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Create a folder "foobar" to hold module content
2. Create a file called package.json in this folder and add:
,----
| {
| "name" : "asimpletest",
| "version" : "1.0.0",
| "main" : "test.js",
| "private" : true
| }
`----
"private" tells npm to never accidentally publish this to the live npm
repository.
Put a link to the package in the local machine's default public
package repository:
,----
| cd baz
| npm link
`----
1. Load `foobar':
,----
| var fb = require('./foobar);
`----
13.6 To publish a module
~~~~~~~~~~~~~~~~~~~~~~~~
1. Remove "private" in the package.json
2. Create an account in the npm registry:
,----
| npm adduser
| npm login
`----
3. Optionally, fill in more fields in package.json
4. Run:
,----
| npm publish
| npm publish --access=public
|
| # there is also
| npm unpublish
`----
13.7 Example 4
~~~~~~~~~~~~~~
13.7.1 The module
-----------------
,----
| class test1 {
| constructor(qwe) {
| this.hej = qwe;
| }
| }
|
| class test2 {
| constructor(qwe) {
| this.hejsan = qwe;
| }
| }
|
| module.exports = {
| test1, test2
| };
`----
13.7.2 the loader
-----------------
,----
| const { test1 } = require('./qq.js');
|
| var m = new test1('mooo');
| console.log(m.hej);
`----
14 File System
==============
14.1 Example 1 - Reading input from stdin
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| process.stdin.resume();
| process.stdin.setEncoding('utf8');
|
| process.stdin.on('data', function(text) {
| process.stdout.write(text.toUpperCase());
| });
`----
14.2 Example 2 - Opening a file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This program will work in a shell but not when executed as a script,
because `handle' is set asynchronously and not found by `fs.read'.
,----
| var fs = require('fs');
|
| var handle;
| var buf = new Buffer(1000);
|
| // asynchronous file open
| fs.open('test.txt', 'r', function(err, fd) {
| handle = fd;
| });
|
| fs.read(handle, buf, 0, 1000, null, function(err, bytesRead, buffer) {
| //^cannot be larger than the buffer allocated above
| console.log(buf.toString());
| fs.close(handle, function() {/* do nothing */});
| });
`----
The proper way to write the above is:
,----
| var fs = require('fs');
|
| fs.open('test.txt', 'r', function(err, fd) {
| var buf = new Buffer(1000);
|
| fs.read(fd, buf, 0, 1000, null, function(err, bytesRead, buffer) {
| console.log(buf.toString());
| fs.close(fd, function() {});
| });
| });
`----
14.3 Example 3 - Reading a directory
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var fs = require('fs');
|
| fs.readdir('/usr/local/bin', function(err, content) {
| if (err) return console.error(err);
|
| console.log(content);
| });
`----
14.4 Example 4 - Reading directory content inside a http server
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var fs = require('fs');
| var http = require('http');
|
| http.createServer(function(req, res) {
| fs.readdir('/home/rand/Apps/', function(err, files) {
| res.writeHead(200, {'Content-Type' : 'application/json'});
| res.end(JSON.stringify(files));
| });
| }).listen(8080);
`----
14.5 Example 5 - Filtering directory content to only directories
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Most loops and asynchronous callbacks are not compatible* Recursion
*should be used instead*
,----
| var fs = require('fs');
| var http = require('http');
|
| http.createServer(function(req, res) {
| fs.readdir('/home/rand/Apps/', function(err, files) {
|
| var dirs = [];
|
| (function filter_dirs(i) {
| if (i == files.length) {
| // send back results
| res.writeHead(200, {'Content-Type' : 'application/json'});
| res.end(JSON.stringify(dirs));
| } else {
| fs.stat('/home/rand/Apps/' + files[i], function(err, stats) {
| if (stats.isDirectory()) {
| dirs.push(files[i]);
| }
|
| filter_dirs(i+1);
| });
| }
| })(0);
| });
| }).listen(8080);
`----
14.6 Example 6 - Get file size in bytes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var fs = require('fs');
|
| fs.stat('/usr/bin/passwd', function(err, stat) {
| console.log('file is ' + stat.size + ' bytes');
| });
`----
14.7 Example 7 - Read a fill using fs.readFile (useful if there is encoding)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var fs = require('fs');
|
| fs.readFile('file.txt', { encoding: 'utf8' }, function(err, content) {
| if (err) return console.error(err);
|
| console.log(content);
| });
`----
Read a binary file:
,----
| var fs = require('fs');
|
| fs.readFile('file.bin', function(err, content) {
| if (err) return console.error(err);
|
| console.log(content.toString('hex'));
| });
`----
14.8 Example 8 - Check file permissions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs.access() determines whether a path exists and what permissions a
user has to the file or directory at that path. fs.access doesn't
return a result rather, if it doesn't return an error, the path exists
and the user has the desired permissions.
Constant Meaning
----------------------------
fs.constants.F_OK Has rwx
fs.constants.R_OK Has r
fs.constants.W_OK Has w
fs.constants.X_OK Has x
,----
| var fs = require('fs');
|
| fs.access('/path/to/file', fs.constants.F_OK, function(err) {
| if (err) return console.err(err);
|
| console.log('all is ok');
| });
`----
15 Diagnostics
==============
15.1 Logging
~~~~~~~~~~~~
,----
| console.log('hello world');
| console.log('hello world: ', name);
| console.log('hello world: %s', name);
|
| // writes to stderr
| console.error('an error message');
`----
15.2 Measuring time
~~~~~~~~~~~~~~~~~~~
To measure the time it takes to run some code.
,----
| console.time('mytimername')
|
| // ... code ...
|
| console.timeEnd('mytimername')
`----
15.3 debug
~~~~~~~~~~
,----
| node debug script.js
`----
To breakpoint your debugger exactly in a code line you want, use this:
,----
| debugger;
`----
15.4 inspect
~~~~~~~~~~~~
,----
| node inspect app.js
`----
Then, *not* in incognito mode in Chrome, type: chrome://inspect
Click "inspect" next to your Node.js process to open up the developer
tools. From there, you can click the blue "play" button near the
top-right of the "sources" tab to start up the application.
16 Operating system
===================
16.1 process
~~~~~~~~~~~~
process is an EventEmitter; events can be subscribed to using the .on
call.
,----
| process; // to see everything
| process.arch; // x64
| process.platform; // linux
| process.memoryUsage();
|
| // command line arguments
| process.argv; // script arguments; argv is an array
| process.argv[2]; // [0] and [1] are always provided
| // ...
| process.pid;
| process.ppid;
|
| // path to the executing node binary
| process.execPath;
|
| // current node release
| process.release;
|
| // current node version
| process.version;
|
| // program exit codes
| process.exit(1); // non-zero means error
| process.exit(0); // exit ok
|
| // environment variables of the operating system
| process.env;
| process.env.HOME;
| process.env.PATH;
|
| process.pid;
|
| process.stdout;
|
| // send any POSIX signals to any processes
| process.kill(pid, [signal]);
|
| // The 'beforeExit' event is emitted when Node.js empties its event
| // loop and has no additional work to schedule. Normally, the Node.js
| // process will exit when there is no work scheduled, but a listener
| // registered on the 'beforeExit' event can make asynchronous calls,
| // and thereby cause the Node.js process to continue.
| process.on('beforeExit', function() {
| // ...
| });
|
| // There is no way to prevent the exiting of the event loop at this
| // point, and once all 'exit' listeners have finished running the
| // Node.js process will terminate.
| process.on('exit', function(code) {
| // ...
| });
|
| process.on('warning', function(warning) {
| console.warn(warning.name); // Print the warning name
| console.warn(warning.message); // Print the warning message
| console.warn(warning.stack); // Print the stack trace
| });
|
| // Emit a warning with a code and additional detail.
| process.emitWarning('Something happened!', {
| code: 'MY_WARNING',
| detail: 'This is some additional information',
| });
|
| // show node.js process command line options
| process.execArgv;
|
| // If you want to run ECMAScript 6 features in older version of
| // nodejs, you can use --harmony flag. Latest version of node supports
| // ES6 so no need of --harmony flag
|
| // node --harmony script.js --version
| // Results in process.execArgv:
| // ['--harmony']
|
| // high resolution time, counted from an arbitrary point in time.
| process.hrtime.bigint(); // in nanoseconds
`----
16.1.1 uncaughtException
------------------------
If no event listeners are added to the uncaughtException handler, the
process will print the stack trace to stderr and exit.
Recovering from uncaughtException is strongly discouraged, it is not
safe to continue normal operation after it.
,----
| process.on('uncaughtException', function(err) {
| // here the 1 is a file descriptor for STDERR
| fs.writeSync(1, `Caught exception: ${err}\n`)
| })
`----
16.1.2 Add a POSIX signal listener
----------------------------------
,----
| process.on('SIGHUP', function() { // SIGHUP = SIGnal Hang UP
| console.log('received SIGHUP signal...');
| });
|
| // the SIGTERM signal is sent to a Node.js process to request its
| // termination. Unlike the SIGKILL signal, it can be listened on or
| // ignored by the process.
|
| process.on('SIGTERM', function() {
| console.log('received SIGTERM signal...');
| });
`----
16.2 require('os')
~~~~~~~~~~~~~~~~~~
,----
| var os = require('os');
|
| // number of cpus
| os.cpus().length;
|
| // memory in bytes
| os.freemem();
| os.totalmem();
|
| // home directory path
| os.homedir(); // /home/rand
|
| // machine hostname
| os.hostname(); // thinkieli
|
| // network interfaces available
| os.networkInterfaces();
|
| // operating system
| os.platform(); // limux
|
| // kernel version
| os.release(); // 5.4.0.29-generic
|
| // path to temp directory
| os.tmpdir();
|
| // show things like username, uid, gid, and shell
| os.userInfo();
|
| // misc info
| os.constants;
`----
17 child processes
==================
,----
| var child_process = require('child_process');
`----
17.1 spawn: runs the program asynchronously, without blocking the event loop
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To spawn a new process in which you need unbuffered output,
e.g. long-running processes which might print output over a period of
time rather than printing and exiting immediately.
,----
| var spawn = require('child_process').spawn;
| var s = spawn('ls', ['-lh', '/home/']);
|
| s.on('error', function(err) { console.log(err); });
| s.on('exit', function(code) { console.log(code); });
|
| s.stdout.on('data', function(data) {
| console.log(data);
| });
|
| s.stderr.on('data', function(data) {
| console.log(data);
| });
|
| s.stdout.pipe(process.stdout);
| s.stderr.pipe(process.stderr);
|
| var cat = spawn('cat', ['test.txt']);
| var sort = spawn('sort');
|
| cat.stdout.pipe(sort.stdin);
`----
17.1.1 Detachment
-----------------
Normally, any child process will be terminated when the parent Node
process is terminated. Child processes are said to be attached to the
parent process. But the spawn method includes the ability to detach a
child process and promote it to be a process group leader. In this
scenario, if the parent is terminated, the child process will continue
until finished. This scenario is useful when you want Node to set up
the execution of a long-running external process and you don’t need
Node to babysit it after it starts.
,----
| var child = child_process.spawn('./longrun', [], { detached: true });
`----
17.1.2 unref
------------
You can use the child.unref() method to tell Node not to include this
child process reference in its count. The following complete
application will now exit after spawning the child process:
,----
| var fs = require('fs');
| var cp = require('child_process');
| var outFd = fs.openSync('./longrun.out', 'a');
| var errFd = fs.openSync('./longrun.err', 'a');
| var child = cp.spawn('./longrun', [], {
| detached: true,
| stdio: [ 'ignore', outFd, errFd ]
| });
| child.unref();
`----
17.2 exec: runs the program in a shell
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The exec method runs the commands with `/bin/sh'. Running commands in
a shell gives access to all the functionality provided by your
particular shell (like pipes, redirects, and backgrounding).
Unlike execFile and spawn, the exec method doesn’t have a separate
argument for command parameters/flags, since you can run more than one
command in a shell.
*Important*: exec buffers any generated output.
,----
| const exec = require('child_process').exec;
|
| exec('cat filename.txt | wc -l', function(err, stdout, stderr) {
| //
| });
`----
17.3 execFile: runs the program without a shell
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
execFile buffers the output for you and provide the results and any
errors in a callback. Having execFile is great for when you want to
just execute an application and get the output (or discard it), for
example, if you want to run an image-processing command with
ImageMagick and only care if it succeeds or not. But if an application
has a lot of output or you want to do more real-time analysis of the
data returned, using streams is a better approach.
,----
| var execFile = require('child_process').execFile;
|
| execFile('echo', ['hello','world'], function(err, stdout, stderr) {
| // ...
| });
`----
17.4 fork
~~~~~~~~~
Execute a Node module as a separate process, given a set of arguments,
provide a streaming and evented interface like spawn, and also set up
an inter-process communication (IPC) channel between the parent and
child process.
,----
| var cp = require('child_process');
| var child = cp.fork('./myChild');
|
| child.on('message', function (msg) {
| console.log('got a message from child', msg);
| });
|
| // IPC (inter-process communication)
| child.send('sending a string');
| child.send('hello');
|
| // in the child process
| process.on('message', function(data) {
| // ...
| });
|
| // used when tracking errors in an application while using the promise
| // constructor. Otherwise such mistakes are silently swallowed
|
| // The 'multipleResolves' event is emitted whenever a Promise has been either:
| // Resolved more than once.
| // Rejected more than once.
| // Rejected after resolve.
| // Resolved after reject.
|
| process.on('multipleResolves', function(type, promise, reason) {
| console.error(type, promise, reason);
| setImmediate(function() { process.exit(1); });
| });
`----
17.5 execSync
~~~~~~~~~~~~~
The child_process.spawnSync(), child_process.execSync(), and
child_process.execFileSync() methods are synchronous and will block
the Node.js event loop, pausing execution of any additional code until
the spawned process exits.
,----
| const { execSync } = require('child_process');
|
| const output = execSync('ls -la');
|
| console.log(output.toString());
`----
18 unit testing
===============
Unit testing refers to automated (scripted) tests. These are scripted
tests written like any other code block. We run our functions with
defined inputs and inspect their effects to ensure they behave as we
expect. When we write new tests alongside the features, we can verify
the entire module still works without having to remember how to use
each function every time. The exam doesn't prescribe a specific
framework, just select one and learn it.
*A set of tests that test a module are called unit tests.*
I selected mocha: [https://mochajs.org/]
,----
| # chai is optional
| npm install mocha chai
`----
To set up the basic tests, create a new folder called "test" in the
project root, then within that folder add a file called test-blaha.js.
`mkdir project/test'
,----
| "scripts": {
| "test": "mocha"
| }
`----
Run `npm test'
There are thre
Syntax for the test script is like this:
18.1 describe("title", function() { ... })
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
What functionality we’re describing. In our case we’re describing the
function pow. Used to group “workers” – the it blocks. The describe()
function is used to group similar tests. It’s not required for Mocha
to run tests, but grouping tests make our test code easier to
maintain. It’s recommended that you group your tests in a way that’s
easy for you to update similar ones together.
18.2 it("use case description", function() { ... })
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In the title of it we in a human-readable way describe the particular
use case, and the second argument is a function that tests it. The
it() contains our test code. This is where we would interact with our
module’s functions and use the assert library. Many it() functions can
be defined in a describe() function.
18.3 assert.equal(value1, value2)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The code inside it block, if the implementation is correct, should
execute without errors.
*Important* Code using *mocha* must be run using the mocha command,
not the regular way of running node code.
18.4 Example 1
~~~~~~~~~~~~~~
18.4.1 project/test/blaha.js
----------------------------
,----
| var assert = require('assert');
| var foobar = require('../index');
|
| describe("a simple test", function() {
| it("moi moi", function() {
| assert.equal(foobar(2,2), 4);
| });
| });
`----
18.4.2 project/index.js
-----------------------
,----
| function foobar(a, b) {
| return a*b;
| }
|
| module.exports = foobar;
`----
18.4.3 project/package.json
---------------------------
,----
| "scripts": {
| "test": "mocha"
| },
`----
18.4.4 final
------------
,----
| cd project
| npm test
`----
18.5 Example 2
~~~~~~~~~~~~~~
,----
| var chai = require('chai');
| var chaiHttp = require('chai-http');
| var server = require('../server/app');
| var should = chai.should();
|
| chai.use(chaiHttp);
|
| describe('Blobs', function() {
| it('should list ALL blobs on /blobs GET', function(done) {
| chai.request(server)
| .get('/blobs')
| .end(function(err, res) {
| res.should.have.status(200);
| done();
| });
| });
|
| it('should list a SINGLE blob on /blob/ GET');
| it('should add a SINGLE blob on /blobs POST');
| it('should update a SINGLE blob on /blob/ PUT');
| it('should delete a SINGLE blob on /blob/ DELETE');
| });
`----
To test, simply run mocha.
18.6 Example 3
~~~~~~~~~~~~~~
,----
| var assert = require('assert');
| describe('Array', function() {
| describe('#indexOf()', function() {
| it('should return -1 when the value is not present', function() {
| assert.equal([1, 2, 3].indexOf(4), -1);
| });
| });
| });
`----
18.7 Asynchronous Code
~~~~~~~~~~~~~~~~~~~~~~
18.7.1 Using async functions
----------------------------
Pass an async function to it(), and Mocha will handle any errors that
occurs.
,----
| const axios = require('axios');
|
| function get(url, cb) {
| return axios.get(url);
| }
|
| describe('get()', function() {
| it('works', async function() {
| const res = await get('http://httpbin.org/get?answer=42');
| assert.equal(res.data.args.answer, 42);
| });
| });
`----
18.7.2 Legacy approach
----------------------
*By adding an argument (usually named done) to it() to a test
callback*, Mocha will know that it should wait for this function to be
called to complete the test. This callback accepts both an Error
instance (or subclass thereof) or a falsy value; anything else is
invalid usage and throws an error (usually causing a failed test).
Make sure you call done()! If you don't call done(), your Mocha test
will time out.
,----
| describe('User', function() {
| describe('#save()', function() {
| it('should save without error', function(done) {
| var user = new User('Luna');
| user.save(function(err) {
| // If you pass a parameter to `done()`, Mocha
| // considers that an error
| if (err) done(err);
|
| // `done()` with no parameters means the test
| // succeeded
| else done();
| });
| });
| });
| });
`----
18.8 Synchronous Code
~~~~~~~~~~~~~~~~~~~~~
When testing synchronous code, omit the callback and Mocha will
automatically continue on to the next test.
,----
| describe('Array', function() {
| describe('#indexOf()', function() {
| it('should return -1 when the value is not present', function() {
| [1, 2, 3].indexOf(5).should.equal(-1);
| [1, 2, 3].indexOf(0).should.equal(-1);
| });
| });
| });
`----
19 Control flow
===============
During the execution of an asynchronous program, some tasks can happen
anytime, independent of what the rest of the program is doing, without
causing problems. But some tasks should happen only before or after
certain other tasks.
The concept of sequencing groups of asynchronous tasks is called flow
control by the Node community. There are two types of flow control:
serial and parallel.
The following code is an example of executing tasks in sequence by
using callbacks. The example uses setTimeout to simulate tasks that
take time to execute: the first task takes one second, the next takes
half of a second, and the last takes onetenth of a second. setTimeout
is only an artificial simulation; in real code you could be reading
files, making HTTP requests, and so on. Although this example code is
short, it’s arguably a bit messy, and there’s no easy way to
programmatically add another task.
,----
| setTimeout(function() {
| console.log('I execute first.');
| setTimeout(function() {
| console.log('I execute next.');
| setTimeout(function() {
| console.log('I execute last.');
| }, 100);
| }, 500);
| }, 1000);
`----
Alternatively, you can use a flow-control tool such as async
([http://caolan.github.io/async/]) to execute these tasks.
,----
| npm install async
`----
19.1 async.series
~~~~~~~~~~~~~~~~~
Instead of nesting async functions, async.series can be used to type
them out serially.
,----
| npm install async
`----
19.1.1 Example 1
----------------
,----
| var async = require('async');
|
| // input is an array of async functions executed one after another
| async.series([
| function (test) {
| setTimeout(function() { console.log('first'); test(); }, 1000);
| },
| function (test) {
| setTimeout(function() { console.log('second'); test(); }, 1000);
| },
| function (test) {
| setTimeout(function() { console.log('third'); test(); }, 1000);
| }
| ]);
`----
,----
| var async = require('async');
|
| async.series([
| function(test) {
| console.log('test 1');
| test();
| },
| function(test) {
| console.log('test 2');
| test();
| },
| function(test) {
| console.log('test 3');
| test();
| }
| ]);
`----
19.1.2 Example 2
----------------
,----
| var results = [];
|
| setTimeout(function() {
| console.log("Task 1");
| results[0] = 1;
| setTimeout(function() {
| console.log("Task 2");
| results[1] = 2;
| setTimeout(function() {
| console.log("Task 3");
| results[2] = 3;
| }, 100);
| }, 200);
| }, 300);
`----
The above can be written as:
,----
| var async = require("async");
|
| async.series([
| function(callback) {
| setTimeout(function() {
| console.log("Task 1");
| callback(null, 1);
| }, 300);
| },
| function(callback) {
| setTimeout(function() {
| console.log("Task 2");
| callback(null, 2);
| }, 200);
| },
| function(callback) {
| setTimeout(function() {
| console.log("Task 3");
| callback(null, 3);
| }, 100);
| }
| ], function(error, results) {
| console.log(results);
| });
`----
19.1.3 Example 3
----------------
,----
| var async = require('async');
|
| async.series([
| function(test) {
| console.log('test 1');
| test(null, 1);
| // ^err is null
| },
| function(test) {
| console.log('test 2');
| test(null, 42);
| },
| function(test) {
| console.log('test 3');
| test(null, 100);
| }],
| function(error, results) {
| console.log(results);
| }
| );
|
`----
19.2 async.parallel
~~~~~~~~~~~~~~~~~~~
Run the tasks collection of functions in parallel, without waiting
until the previous function has completed. If any of the functions
pass an error to its callback, the main callback is immediately called
with the value of the error. Once the tasks have completed, the
results are passed to the final callback as an array.
The first argument is an array of the asynchronous functions to
run. Run multiple tasks independent of each other without waiting
until the previous task has completed:
19.2.1 Example 1
----------------
,----
| var async = require("async");
|
| async.parallel({
| foo: function(callback) { callback(null, 1); },
| bar: function(callback) { callback(null, 2); },
| baz: function(callback) { callback(null, 3); }
| },
| // optional callback
| function(err, results) {
| // 'results' is now equal to: {foo: 1, bar: 2, baz: 3}
| });
`----
19.2.2 Example 2
----------------
,----
| var async = require('async');
|
| async.parallel({
| one: function(callback) {
| setTimeout(function() {
| callback(null, 1);
| }, 200);
| },
| two: function(callback) {
| setTimeout(function() {
| callback(null, 2);
| }, 100);
| }
| }, function(err, results) {
| // results is now equals to: {one: 1, two: 2}
| console.log(results);
| });
`----
19.3 async.waterfall
~~~~~~~~~~~~~~~~~~~~
Runs the tasks array of functions in series, each passing their
results to the next in the array. However, if any of the tasks pass an
error to their own callback, the next function is not executed, and
the main callback is immediately called with the error.
async.waterfall(tasks, [callback])
- tasks – An array of functions to run, each function is passed a
callback(err, result1, result2, ...) it must call on completion. The
first argument is an error (which can be null) and any further
arguments will be passed as arguments in order to the next task.
- callback(err, [results]) – An optional callback to run once all the
functions have completed. This will be passed the results of the
last task’s callback.
,----
| var async = require("async");
|
| async.waterfall([
| function(callback) {
| callback(null, 'one', 'two');
| },
| function(arg1, arg2, callback) {
| // arg1 now equals 'one' and arg2 now equals 'two'
| callback(null, 'three');
| },
| function(arg1, callback) {
| // arg1 now equals 'three'
| callback(null, 'done');
| }
| ], function (err, result) {
| // result now equals 'done'
| console.log(result);
| });
`----
20 Promises
===========
A promise is basically an advancement of callbacks in Node so that
functions don't need to be nested (i.e. a way to avoid "callback
hell"). This results in more readable code. While developing an
application you may encounter that you are using a lot of nested
callback functions. To enable Promise-based execution, asynchronous
callback-based functions must be changed so they immediately return a
Promise object.
Any promise that performs async operations should call any one of the
two methods resolve or reject. The code logic should take care of when
and where to call these functions. If the operation is successful,
pass that data to the code that uses that promise, otherwise pass
error.
The code which uses a promise should call then function on that
promise. It takes two anonymous functions as parameters. The first
function executes if the promise is resolved and the second function
executes if promise is rejected.
What happens if you try to access the value from promise before it is
resolved or rejected. Then promise will be in the pending state.
,----
| // resolve and reject are callbacks
| function myFunc() {
| var promise = new Promise(function(resolve, reject) {
| // do the async job here
| doSomethingAsync(function(err) {
| if (err) {
| reject(err);
| } else {
| resolve(42);
| }
| });
|
| });
|
| return promise;
| }
|
| myFunc().then(function(foo) { console.log('success: ' + foo); },
| function(err) { console.log('error: ' + err); });
`----
The promise object returned by the new Promise constructor has these
internal properties. The properties state and result of the Promise
object are internal. We can’t directly access them. We can use the
methods .then/.catch/.finally for that. They are described below.
state — initially "pending", then changes to either "fulfilled" when
resolve is called or "rejected" when reject is called.
result — initially undefined, then changes to value when
resolve(value) called or error when reject(error) is called.
20.1 using "then"
~~~~~~~~~~~~~~~~~
20.1.1 Example 1
----------------
,----
| // resolve runs the first function in .then
| promise.then(
| // this function is launched if the promise runs resolve();
| function(result) {
| // ...
| },
| // this function is launched if the promise runs reject();
| function(error) {
| //
| }
| );
|
| function foobar() {
| return new Promise(function(resolve, reject) {
| console.log('hello 42 world');
|
| if (true) {
| resolve();
| } else {
| reject();
| }
| });
| }
|
| foobar().then(function(results) {
| console.log('test');
| },
| function(error) {
| console.log('rejection');
| });
`----
,----
| function foobar() {
| return new Promise(function(resolve, reject) {
| console.log('hello 42 world');
| resolve();
| });
| }
|
| foobar().then(function(results) {
| console.log('test');
|
| var qq = new Promise(function(resolve, reject) { resolve('huhgu'); });
|
| return qq;
| }).then(function(res) {
| console.log(res);
| });
`----
20.1.2 Example 2
----------------
When a handler returns a value, it becomes the result of that promise,
so the next .then is called with it.
,----
| new Promise(function(resolve, reject) {
| setTimeout(function() { resolve(1), 1000); };
| }).then(function(result) {
| console.log(result);
| return result * 2;
| }).then(function(result) {
| console.log(result);
| return result * 2;
| }).then(function(result) {
| console.log(result);
| return result * 2;
| });
`----
20.2 util.promisify
~~~~~~~~~~~~~~~~~~~
`util.promisify(object);' can be used to return an object version that
returns a promise. promisify() assumes that original is a function
taking a callback as its final argument in all cases. If original is
not a function, promisify() will throw an error. If original is a
function but its last argument is not an error-first callback, it will
still be passed an error-first callback as its last argument.
Anything that returns a Promise can start a series of asynchronous
function calls defined in .then() methods. Each is passed the result
from the previous resolve.
,----
| const util = require('util');
| const fs = require('fs');
|
| const stat = util.promisify(fs.stat);
| stat('.').then(function(stats) {
| // do something with stats
| }).catch(function(error) {
| // handle the error
| });
`----
20.3 examples
~~~~~~~~~~~~~
,----
| // using callbacks
| fetchCallback("url", err => {
| if (err) return console.log(err);
| fetchCallback("url", err => {
| if (err) return console.log(err);
| fetchCallback("url", err => {
| if (err) return console.log(err);
| fetchCallback("url", err => {
| if (err) return console.log(err);
| console.log("all done");
| });
| });
| });
| });
|
| // using Promises
| fetch("url")
| .then(function(result) { return fetch("url"); })
| .then(function(result) { return fetch("url"); })
| .then(function(result) { return fetch("url"); })
| .then(function(result) { return fetch("url"); })
| .then(function(result) { return console.log("all done"); })
| .catch(function(err) { console.log(err); });
`----
Another example:
,----
| someAsyncFunction()
| .then(function(data) {
| // after promise is fulfilled
| console.log(data);
| })
| .catch(err => {
| // If promise is rejected
| console.error(err);
| });
`----
20.4 alternative to promise.then
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20.4.1 async
------------
The word "async" before a function means one simple thing: a function
always returns a Promise object. Other values are wrapped in a
resolved promise automatically. async ensures that the function
returns a promise even if you don’t explicitly write them to do so,
and wraps non-promises in it.
The await keyword is only available inside async functions at the
moment - it cannot be used in the global scope.
This function returns a resolved promise with the result of 1:
,----
| async function f() {
| return 1;
| }
|
| f().then(alert); // 1
`----
The async keyword before a function has two effects:
- Makes it always return a promise.
- Allows await to be used in it.
20.4.2 await
------------
Works only inside async functions. The keyword await makes JavaScript
wait until that promise settles and returns its result.
With chaining:
,----
| function fun1(req, res) {
| return request.get('http://localhost:3000')
| .catch(function(err) {
| console.log('found error');
| }).then(function(res) {
| console.log('get request returned.');
| });
| }
`----
With async/await:
,----
| async function fun1(req, res){
| let response = await request.get('http://localhost:3000');
|
| if (response.err) {
| console.log('error');
| }
| else {
| console.log('fetched response');
| }
| }
`----
,----
| const util = require('util');
| const exec = util.promisify(require('child_process').exec);
|
| async function lsExample() {
| const { stdout, stderr } = await exec('ls');
| console.log('stdout:', stdout);
| console.log('stderr:', stderr);
| }
|
| lsExample();
`----
,----
| function who() {
| return new Promise(resolve => {
| setTimeout(function() {
| resolve('qwe');
| }, 202);
| });
| }
|
| function what() {
| return new Promise(resolve => {
| setTimeout(function() {
| resolve('foobar');
| }, 301);
| });
| }
|
| function where() {
| return new Promise(resolve => {
| setTimeout(function() {
| resolve('hello world');
| }, 500);
| });
| }
|
| async function msg() {
| const a = await who();
| const b = await what();
| const c = await where();
|
| console.log(`${ a } ${ b } ${ c }`);
| }
|
| msg();
`----
20.5 errors
~~~~~~~~~~~
,----
| const p = new Promise(function (resolve, reject) {
| reject(new Error('Oops'));
| });
| // anything that is `reject`ed inside a promise will be available through catch
| // while a promise is rejected, `.then` will not be called
| p.then(function() {
| console.log("won't be called");
| }).catch(function(err) {
| console.log(err.message);
| }).then(function() {
| // once the error is caught, execution flow resumes
| console.log('hello!'); // output: hello!
| });
`----
21 paths
========
,----
| var path = require('path');
|
| // provides the platform-specific path segment separator
| path.sep;
|
| // resolves relative paths to absolute paths
| path.resolve('../../'); // prints "/home"
|
| // print current folder
| path.resolve();
|
| // same as the linux command
| path.basename('/dsfdsf/test/foobar'); // foohar
|
| path.dirname('/hej/test/foobar'); // /hej/test
|
| // returns the extension
| path.extname('/dsfdsf/test/foobar.txt'); // .txt
|
| // determines if path is an absolute path
| path.isAbsolute('/usr/sbin/test'); // true
|
| // joins all given path segments together using
| // the platform-specific separator as a delimiter,
| // then normalizes the resulting path.
| path.join('/foo', 'bar', 'baz/asdf', 'quux', '..'); // /foo/bar/baz/asdf
|
| // When multiple, sequential path segment separation characters are
| // found (e.g. / on POSIX and either \ or / on Windows), they are
| // replaced by a single instance of the platform-specific path segment
| // separator (/ on POSIX and \ on Windows). Trailing separators are
| // preserved.
| path.normalize('/foo/bar//baz/asdf/quux/..'); // /foo/bar/baz/asdf
|
| // parse returns an object whose properties represent significant
| // elements of the path
| path.parse('/home/user/dir/file.txt');
|
| // Returns:
| // { root: '/',
| // dir: '/home/user/dir',
| // base: 'file.txt',
| // ext: '.txt',
| // name: 'file' }
|
| // path.relative() method returns the relative path
| // from from to to based on the current working directory
| path.relative('/usr/sbin/', '/usr/');
`----
22 perf_hooks (performance metrics)
===================================
22.1 Example 1
~~~~~~~~~~~~~~
,----
| const { PerformanceObserver, performance } = require('perf_hooks');
|
| const obs = new PerformanceObserver(function(items) {
| console.log(items.getEntries()[0].duration);
| performance.clearMarks();
| });
|
| obs.observe({ entryTypes: ['measure'] });
|
| performance.mark('A');
|
| setTimeout(function() {
| performance.mark('B');
| performance.measure('A to B', 'A', 'B');
| }, 1234);
`----
22.2 Example 2 -- timerify
~~~~~~~~~~~~~~~~~~~~~~~~~~
Wraps a function within a new function that measures the running time
of the wrapped function.
,----
| const {
| performance,
| PerformanceObserver
| } = require('perf_hooks');
|
| function someFunction() {
| console.log('hello world');
| }
|
| const wrapped = performance.timerify(someFunction);
|
| const obs = new PerformanceObserver((list) => {
| console.log(list.getEntries()[0].duration);
| obs.disconnect();
| });
| obs.observe({ entryTypes: ['function'] });
|
| // A performance timeline entry will be created
| wrapped();
`----
23 querystring
==============
,----
| var qs = require('querystring');
|
| // parse / decode (aliases)
| qs.parse('foo=bar&abc=xyz&abc=123'); // { foo: 'bar', abc: [ 'xyz', '123' ] }
|
| // stringify / encode (aliases)
| const jsonExample = {
| title: 'This is the title of the Article',
| resume: 'Praesent elementum facilisis leo vel fringilla est ullamc',
| test: '42'
| };
|
| qs.encode(jsonExample);
`----
24 readline
===========
24.1 Example 1
~~~~~~~~~~~~~~
Reading data from a Readable stream (such as process.stdin) one line
at a time.
,----
| var rl = require('readline');
|
| const rli = rl.createInterface({
| input: process.stdin,
| output: process.stdout
| });
|
| rli.question('What is XYZ?', function(answer) {
| console.log(`Input: ${answer}`);
| rli.close();
| });
|
| // The 'SIGINT' event is emitted whenever the input stream receives a
| // -C input.
| rli.on('SIGINT', () => {
| console.log('Event SIGINT.');
| rli.question('Are you sure you want to exit? ', function(answer) {
| if (answer.match(/^y(es)?$/i)) rli.pause();
| });
| });
|
| // The 'SIGTSTP' event is emitted when the input stream receives a
| // -Z input.
| rli.on('SIGTSTP', () => {
| console.log('Event SIGTSTP.');
| });
`----
24.2 Example 2 - Read one line at a time
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
,----
| var rl = require('readline');
| var fs = require('fs');
|
| var q = readline.createInterface({
| input: fs.createReadStream('test.txt')
| });
|
| q.on('line', function(line) {
| console.log(line);
| });
|
| q.on('close', function() {
| console.log('done');
| });
`----
25 fs (file system)
===================
,----
| fs.statSync('/home/rand/Downloads').isDirectory(); // true
| fs.statSync('/home/rand/Downloads').isFile(); // false
|
| // asynchronously changes the permissions of a file
| fs.chmod(path, mode, callback);
|
| fs.chown(path, uid, gid, callback)
|
| fs.copyFile('/path/to/file');
|
| fs.link(existingPath, newPath, callback)
|
| fs.mkdir(path, callback);
|
| // creates a unique temporary directory
| fs.mkdtemp(prefix);
|
| fs.rename(oldPath, newPath, callback)
|
| fs.rmdir(path);
|
| // delete files
| fs.unlink('/path/to/file', function(err) {
|
| });
|
| // watch for changes on filename, where filename is either a file or a
| // directory
| fs.watch('/path/to/file');
|
| // check if a file exists
| fs.stat('/path/to/file', function(err) {
| if (!err) {
| console.log('file exists');
| } else if (err.code == 'ENOENT') {
| console.log('does not exist');
| }
| });
`----
26 semantic versioning
======================
The NPM ecosystem uses Semantic Versioning (SemVer) which follows the
convention of MAJOR.MINOR.PATCH (e.g. 1.3.2). This is to differentiate
between versions that introduce major breaking changes, minor
backwards-compatible changes, and patch changes for small fixes.
Example package.json dependency entry:
,----
| "dependencies": {
| "request": "^2.88.0"
| }
`----
By default, npm prefixes a caret ^ before the version number of an
installed dependency.
^: if you write ^0.13.0 when running npm update it can update to patch
and minor releases: 0.13.1, 0.14.0 and so on.
The caret specifies we can update to any version greater than 2.88.0
within this major version. In the above example, the major version is
2. Anything > 2.88.0 and < 3.0.0 is valid. However, the caret behavior
changes when a package version is still below 1.0.0.
Note: When a package version is below 1.0.0 (e.g. ^0.2.5), a caret
will only let us update patch versions, and not minor or major
versions. In theory, this allows us to safely upgrade to versions that
are backward-compatible and not considered breaking changes.
Rule Description
-----------------------------------------------------------------
^ update to minor and patch versions (if version is >1.0.0)
^ update to patch versions (if version is < 1.0.0)
~ it can update to patch releases only
> higher versions
< lower versions
- range
= exactly this version
There is also ||, i.e. < 2.1 ¦¦ > 2.6
27 package.json
===============
27.1 scripts
~~~~~~~~~~~~
,----
| {
| "name": "your-package",
| "version": "1.0.0",
| "description": "",
| "main": "index.js",
| "author": "",
| "license": "ISC",
| "dependencies": {},
| "devDependencies": {},
| "scripts": {
| "echo": "echo hello!"
| }
| }
`----
Then run it using:
`npm run echo'
27.2 dependency types
~~~~~~~~~~~~~~~~~~~~~
There are a number of different types of dependencies that you can
have (e.g. dependencies, devDependencies, and peerDependencies).
,----
| {
| "name": "my-project",
| "dependencies": {
| "package-a": "^1.0.0"
| },
| "devDependencies": {
| "package-b": "^1.2.1"
| },
| "peerDependencies": {
| "package-c": "^2.5.4"
| },
| "optionalDependencies": {
| "package-d": "^3.1.0"
| }
| }
`----
+--------------------+------------------------------------------------------------+
|Type |Description |
+--------------------+------------------------------------------------------------+
|dependencies |normal dependencies, or rather ones that you need when |
| |running your code |
+--------------------+------------------------------------------------------------+
|devDependencies |Dependencies that you need at some point in the development |
| |workflow but not while running your code |
+--------------------+------------------------------------------------------------+
|optionalDependencies|This is useful for dependencies that won’t necessarily work |
| |on every machine and you have a fallback plan in case they |
| |are not installed (e.g. Watchman). |
| | |
+--------------------+------------------------------------------------------------+
|peerDependencies |A plugin package is meant to be used with another "host" |
| |package, even though it does not always directly use the |
| |host package, e.g. chai, and thus are not captured by the |
| |package manager's version handling logic. |
+--------------------+------------------------------------------------------------+
28 node executable
==================
28.1 command line flags
~~~~~~~~~~~~~~~~~~~~~~~
+---------------------+---------------------------------------------------------+
| Flag |Description |
+---------------------+---------------------------------------------------------+
| --zero-fill-buffers |Automatically zero-fills all newly allocated Buffer and |
| |SlowBuffer instances. |
+---------------------+---------------------------------------------------------+
| --check |check the syntax of the provided file, without actually |
| |executing it. |
+---------------------+---------------------------------------------------------+
| --eval |run JavaScript code right from your terminal: $ node -e |
| |'console.log(3 + 2)' |
+---------------------+---------------------------------------------------------+
| -r/--require |Preload a specified module at startup. |
| | |
| |For example: node -r assert |
| | |
| |(and assert can be used without calling 'require') |
+---------------------+---------------------------------------------------------+
| -p |Evaluate the string and print the results. |
| | |
| |For example: node -p "console.log('hello world');" |
+---------------------+---------------------------------------------------------+
28.2 exit codes
~~~~~~~~~~~~~~~
+------+-------------------------------------------------------------------+
| Code |Description |
+------+-------------------------------------------------------------------+
| 0 |OK |
+------+-------------------------------------------------------------------+
| 1 |Uncaught fatal exception, which was not handled by an |
| |uncaughtException handler. |
+------+-------------------------------------------------------------------+
| 5 |Fatal error in V8 (like memory allocation failures). |
+------+-------------------------------------------------------------------+
| 9 |Argument, when an unknown option was specified, or an option which |
| |requires a value was set without the value. |
+------+-------------------------------------------------------------------+