Notes On Node.JS
Table of Contents
node -v # v11.2.0
nvm --version # 0.33.11
nvm ls # List installed versions
# system, node, iojs
npm --version # 6.4.1
Node uses Google’s V8 JavaScript engine for language implementation. New language features in Node depend on them being implemented first in V8.
https://node.green/ lists ES6 (2015), etc compatibility.
To find Chrome V8 engine version:
node -v
v11.2.0 # Node version
node -p process.versions.v8
7.0.276.38-node.11 # Chrome V8 engine version
Grunt and Gulp are 2 most popular task runners.
.travis.yml is a testing config file using Travis CI. .jshintrc is for JS linter. jslint and jshint are popular linters. confg.js is a config file. NODE_ENV=my_env_name node index.js
airbnb/javascript gives javascript style guide.
Note: In Client-side rendering, your browser downloads a minimal HTML page. It renders the JavaScript and fills the content into it. Server-side rendering, on the other hand, renders the React components on the server. The output is HTML content.
Electrode is a platform for building universal React/Node.js applications with standardized structure, best practices, and modern technologies baked in.
Synopsis :
npm install gulp --save # It will update ./package.json
# with dependencies as "gulp"
The AWS Amplify CLI is a toolchain for mobile and web app development.
https://github.com/aws-amplify/amplify-cli
package.json dependencies can specify version like 1.x which means
the latest minor version of major version 1.
Legacy style is to call f(p1, p2, callback_func)
Better is to use promise and function chaining so that you call, f(p1, p2).then(cb) because indentation is better and you can call then() later point of time.
Even better is to use await: let result = await f(p1, p2);
Promise chaining can be useful to build async dependent calls.
Calling promise.then(cb) multiple times amount to specifying multiple handlers for the same promise. They execute independently once the initial promise resolves.
You should never throw() from inside of promise handlers. The promise.catch(error) is different from try { } catch(err) synax -- the .catch() is just a plain function call which captures the return value of reject() function.
To make async function call look like sync, you can do :
export function promiseValue(p)
{
return (async (pr) => await pr.then( (v) => v ) )(p)
}
app.get('/', my_callback_func)
Example: Before async/await :
function fun1(req, res){
return request.get('http://localhost:3000')
.catch((err) =>{
console.log('found error');
}
}).then((res) =>{
console.log('get request returned.');
});
The code basically says that GET localhost:3000, catch the error if there is any; if there is no error then implement the following statement: console.log(‘get request returned.’);
The above code demos a function implemented with function chaining instead of callbacks. To be able to use function chaining, the function request.get() must return "a Promise" type which supports .then() method.
With Node v8, the async/await feature was officially rolled out by the Node to deal with Promises and function chaining. The functions need not to be chained one after another, simply await the function that returns the Promise. But the function async needs to be declared before awaiting a function returning a Promise. The code now looks like below.
Example: After 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');
}
Explanation:
The code above basically asks the javascript engine running the code to wait for the request.get() function to complete before moving on to the next line to execute it. The request.get() function returns a Promise for which user will await
The return values of .then() functions are "promisified" so that you can make use of promise() chaining. :
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
}).then(function(result) {
alert(result); // 1
return new Promise((resolve, reject) => { // (*)
setTimeout(() => resolve(result * 2), 1000);
});
}).then(function(result) { // (**)
alert(result); // 2
return 4; // Value 4 is wrapped as resolved Promise().
}).then(function(result) {
alert(result); // 4
});
function httpGet(url) {
return new Promise(
function (resolve, reject) {
const request = new XMLHttpRequest();
request.onload = function () {
if (this.status === 200) {
// Success
resolve(this.response);
} else {
// Something went wrong (404 etc.)
reject(new Error(this.statusText));
}
};
request.onerror = function () {
reject(new Error(
'XMLHttpRequest Error: '+this.statusText));
};
request.open('GET', url);
request.send();
});
}
This is how you use httpGet():
httpGet('http://example.com/file.txt')
.then(
function (value) {
console.log('Contents: ' + value);
},
function (reason) {
console.error('Something went wrong', reason);
});
The promisify function is built-in into node 8. No need to use bluebird. :
const fs = require('fs')
const { promisify } = require('util') // util is built-in for Node 8
const readFile = promisify(fs.readFile)
function isPromise(value) {
return Boolean(value && typeof value.then === 'function');
}
See Also:
// ES5
var name = 'Mukul Latiyan';
console.log('My name is '+ name);
// ES6
const name1 = 'Mukul Latiyan';
console.log(`My name is ${name1}`);
Object unpacking is supported.
Object unpacking :
// ES6
const college = {
name : 'DTU',
established : '1941',
isPrivate : false
};
let{name,established,isPrivate} = college;
Array unpacking :
// ES6
const arr = ['lionel','messi','barcelona'];
let[value1,value2,value3] = arr;
// ES5
function fun(a,b){
b = (typeof b!=='undefined')?b:1;
return a + b;
}
console.log(fun(2,1)); // 3
console.log(fun(2)); // 3
// ES6
function fun(a,b=1){
return a + b;
}
// classes in ES6
class Vehicle{
constructor(name,engine){
this.name = name;
this.engine = engine;
}
}
const bike1 = new Vehicle('Ninja ZX-10R','998cc');
============= extends =====================
class formatDate extends Date {
constructor(dateStr) {
super(dateStr);
}
getFormattedDate() {
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
return `${this.getDate()}-${months[this.getMonth()]}-${this.getFullYear()}`;
}
}
console.log(new formatDate('August 19, 1975 23:15:30').getFormattedDate());
// expected output: "19-Aug-1975"
================ static method ====================
class ClassWithStaticMethod {
static staticMethod() {
return 'static method has been called.';
}
}
console.log(ClassWithStaticMethod.staticMethod());
// expected output: "static method has been called."
This is a default import:
// B.js
import A from './A'
It only works if A has the default export:
// A.js
export default 42
In this case it doesn’t matter what name you assign to it when importing:
// B.js
import A from './A'
import MyA from './A'
import Something from './A'
Because it will always resolve to whatever is the default export of A.
This is a named import called A:
import { A } from './A'
It only works if A contains a named export called A:
export const A = 42
// B.js
import { A } from './A'
import { myA } from './A' // Doesn't work!
import { Something } from './A' // Doesn't work!
To make these work, you would add a corresponding named export to A:
// A.js
export const A = 42
export const myA = 43
export const Something = 44
A module can only have one default export, but as many named exports as
you'd like (zero, one, two, or many). You can import them all together:
// B.js
import A, { myA, Something } from './A'
Here, we import the default export as A, and named exports called myA and
Something, respectively.
// A.js
export default 42
export const myA = 43
export const Something = 44
We can also assign them all different names when importing:
// B.js
import X, { myA as myX, Something as XSomething } from './A'
// ES6 rest parameter
// function f(a, b, ...theArgs) { }
function fun(...input){
let sum = 0;
for(let i of input){
sum+=i;
}
return sum;
}
console.log(fun(1,2,3)); // 6
console.log(fun(1,2,3,4,5)); // 15
function sum(...theArgs) {
return theArgs.reduce((previous, current) => {
return previous + current;
});
}
console.log(sum(1, 2, 3));
// expected output: 6
// Spread operator
let arr = [1,2,3,-1];
console.log(Math.min(...arr)); // -1
function sortArguments() {
// arguments is object. But arguments[0] is first element.
var args = Array.from(arguments);
var sortedArgs = args.sort();
return sortedArgs;
}
console.log(sortArguments(5, 3, 7, 1));
// ============== setter =================
var language = {
set current(name) {
this.log.push(name);
},
log: []
}
language.current = 'EN';
language.current = 'FA';
console.log(language.log);
// expected output: Array ["EN", "FA"]
// ============== getter =================
var obj = {
log: ['a', 'b', 'c'],
get latest() {
if (this.log.length == 0) {
return undefined;
}
return this.log[this.log.length - 1];
}
}
console.log(obj.latest);
// expected output: "c"
var materials = [ 'Hydrogen', 'Helium', 'Lithium', 'Beryllium' ];
console.log(materials.map(material => material.length));
::
const a = ["a", "b", "c"]; for (const val of a) { console.log(val); }
You may want to use prettier command installed on your system and also enable prettier plugin for eslint. This enables running prettier automatically as part of lint stage from vim. :
yarn add --dev prettier eslint-config-prettier eslint-plugin-prettier
sudo yarn global add prettier
Unless you share node_modules, you may be wasting lot of space. The search path goes upwards in directory level. For example, keep node_modules at /home/user, /opt, /disk, etc. My configuration :
/disk/nodebin
html2body.js
pre2pretty.js
....
/disk/node_modules
domutils
lodash
....
const FOO = 'bar';
module.exports = {
FOO
}
import in bar.js
const {FOO} = require('foo');
It is very simple compared to other methods of /etc/ configs :
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('./keys/key.pem'),
cert: fs.readFileSync('./keys/cert.pem')
};
https.createServer(options, function (req, res) {
res.writeHead(200); // .... ; res.end("hello world\n");
}).listen(8000);
$ node inspect myindex.js
# Insert debugger; statements with in source code.
debug> cont
debug> repl
>
For generating lint warnings :
$ node --use_strict myindex.js
For measuring time/performance between calls, use require('perf_hooks')
::
exports.my_func = my_func module.exports.my_func = my_func # Same as
above export my_func # Same as above
Conventional Use:
ES6 Style:
Yarn is superset of NPM. It installs packages in parallel and uses the same NPM registry.
Babel is a JS transpiler that converts new JS code into old ones.
Here is an example — a code written in ES6:
class Test {
calculatePowers() {
return [1,2,3].map(n => n ** 2);
}
}
--------------------------------------------------------------------------
Babel will transpile this code to the following, given the presets es2015:
--------------------------------------------------------------------------
"use strict";
var _createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor; };
}();
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var Test = function () {
function Test() { _classCallCheck(this, Test); }
_createClass(Test, [{
key: "calculatePowers",
value: function calculatePowers() {
return [1, 2, 3].map(function (n) {
return Math.pow(n, 2);
});
}
}]);
return Test;
}();
Webpack is a modular build tool that has two sets of functionality — Loaders and Plugins.
Plugins are the core of Webpack.
Synopsis:
sudo npm install -g yarn
# --dev adds packages.json "DevDependencies" entry
yarn add --dev webpack babel-core babel-loader babel-preset-react
babel-preset-es2015 node-sass css-loader sass-loader style-loader
# Only these pkgs will be installed in production.
yarn add react react-dom
=================== Source Code ==============================
src/
/index.jsx
/index.html
/components
/HelloWorld.jsx
/styles
/app.scss
/components
/hello-world.scss
==============================================================
packages.json :
scripts: {
"build": "webpack -p"
}
# The build produces bundle.js file in output dir
# Can be configured by webpack config file.
# webpack converts single index.js file into bundle.js file
# by following the dependencies starting from index.js.
yarn run build # This needs devDependencies packages.
yarn run dev # Run dev server as defined in packages.json script.
npm install aws-amplify-angular --save
npm install aws-amplify-vue --save
npm install aws-amplify-react-native --save
These files contains original line information for the minified javascript/css files that would be useful for debugging in production. e.g. jquery.min.js and jquery.min.js.map file can help you generated better error message that would be useful to debug using original jquery.js later.
state = { name : 'Raja', age: 40 }
myState ={ ...state, name: 'thava' }
destObj = { ..obj1, ..obj2 }
destObj = Object.assign({}, obj1, obj2)
Also See: my_array.filter(), my_array.map() returns duplicated values.
yarn add esm
node -r esm myfile.js
promise mechanism enables to execute the function and delay the callback logic much later :
promise = execute async function ...
...
promise.then( callback func which does something )
....
promise.then( another callback func for same event )
let promise = new Promise(function(resolve, reject) {
// the function is executed automatically when the promise is constructed
// after 1 second signal that the job is done with the result "done"
setTimeout(() => resolve("done"), 1000);
}
Promise constructor executes given function passing it's internal
implementation of resolve and reject. We never implement resolve().
The resulting promise object has internal properties:
state — initially "pending", then fulfilled | rejected | settled"
result — Anything string or number etc. initially undefined.
// .then() synchronously waits for the result.
promise.then( result => alert(result), // shows "done!" after 1 second
The async mechanism is even better as it helps to create multiple promises on demand. The async function return values are automatically wrapped by resolved promise value :
async function f() {
return 1;
}
f().then(alert); // 1
async function f() {
return Promise.resolve(1); // same as return 1
}
f().then(alert); // 1
// works only inside async functions
let value = await promise;
RxJS combines Observables and Operators so we can subscribe to streams and react to changes using composable operations.
rx = require('rxjs')
$scope.counter = 0;
rx.Observable
.interval(1000) // Creates interval stream of 0, 1, 2, ...
.take(3) // Takes only first 3 in the stream.
.safeApply($scope, function(x) { // Stream operator
$scope.counter = x;
})
.subscribe(); // shows 0, 1, 2 // Triggers Action.
An Observer can do actions on Observable :
var observer = rx.Observer.create(
function onNext(result){
console.log(result);
},
function onError(err){
console.log(err);
},
function onCompleted(){
console.log('Completed');
}
);
observable.subscribe(observer);
// Since version 2.2, RxJS integrates with Promises using
// Rx.Observable.fromPromise.
//
// Operators like create, fromPromise, fromEvent etc creates Observables
// given promise or event object, etc.
Concretely, a higher-order component is a function that takes a component and returns a new component.
Example:
# In App.js, import the withAuthenticator HOC at the top of the file:
import { withAuthenticator } from 'aws-amplify-react'
# And, at the bottom, update the export statement to wrap the App component
export default withAuthenticator(App)
Use http://mlab.com