Node.js
An introduction
Roberto Casadei
Concurrent and Distributed Programming course
Department of Computer Science and Engineering (DISI)
Alma Mater Studiorum – Università of Bologna
June 16, 2018
PCD1718 Introduction NodeJS in practice Async programming in Node 1/32
Outline
1 Introduction
2 NodeJS in practice
3 Async programming in Node
PCD1718 Introduction NodeJS in practice Async programming in Node 2/32
Node.js » intro
Node.js is a JS runtime environment that processes incoming events in a loop,
called the event loop.
Node.js provides an event-driven architecture and a non-blocking I/O API that
optimizes an application’s throughput and scalability.
This model is commonly used to design high-performance real-time web apps.
Support any PL that can compile to JS (e.g., CoffeeScript, TypeScript)
Builds on Google V8 JavaScript engine
Node.js uses libuv to handle asynchronous events
Libuv is an abstraction layer for network and file system functionality on both
Windows and POSIX-based systems
Libuv provides cross-platform asynchronous I/O
Small core + rich userland of simple modules » NPM (Node Package Manager)
PCD1718 Introduction NodeJS in practice Async programming in Node 3/32
Node.js » system overview
PCD1718 Introduction NodeJS in practice Async programming in Node 4/32
Node.js » event loop I
The event loop is what allows Node.js to perform non-blocking I/O ops (despite the
fact that JS is single-threaded) by offloading operations to the system kernel
When one of these operations completes, the kernel tells Node.js so that the
appropriate callback may be added to the poll queue to eventually be executed.
When Node.js starts
1) Initializes the event loop
2) Processes the provided input script
This may make async API calls, schedule timers, or call process.nextTick()
3) Begins processing the event loop
Until no more events are available
PCD1718 Introduction NodeJS in practice Async programming in Node 5/32
Node.js » event loop II
Event loop structure
Consists of phases. Each phase has a FIFO queue of callbacks to execute
On a phase, Node.js runs any operations specific to that phase, then runs
callbacks in that phase’s queue (until empty queue or max num of callbacks are
executed), then moves to the next phase.
Since any op may schedule more ops and new events processed in the poll
phase are queued by the kernel, poll events can be queued while polling
events are being processed.
Between each run of the event loop, Node.js checks if it is waiting for any
asynchronous I/O or timers and shuts down cleanly if there are not any.
PCD1718 Introduction NodeJS in practice Async programming in Node 6/32
Node.js » event loop III
Event loop phases
timers: executes callbacks scheduled by setTimeout() and setInterval()
A timer specifies the threshold after which a provided callback may be executed
rather than the exact time a person wants it to be run.
pending I/O callbacks: execs almost all callbacks with exception of close
callbacks, the ones scheduled by timers, and setImmediate
idle, prepare: only used internally
poll: retrieve new I/O events; node will block here when appropriate
Two main functions:
1) Executing scripts for timers whose threshold has elapsed, then
2) Processing events in the poll queue
To prevent the poll phase from starving the event loop, libuv also has a hard
maximum (system dependent) before it stops polling for more events.
check: setImmediate callbacks are invoked here
close callbacks: e.g., socket.on('close',...)
See Node.js doc & libuv for more details.
PCD1718 Introduction NodeJS in practice Async programming in Node 7/32
Modules and packages On JavaScript Examples
Outline
1 Introduction
2 NodeJS in practice
Modules and packages
On JavaScript
Examples
3 Async programming in Node
PCD1718 Introduction NodeJS in practice Async programming in Node 8/32
Modules and packages On JavaScript Examples
Node toolchain
node
node: starts REPL
node <file.js>: runs given script
npm (Node Package Manager)
Automatically installed with node
Commands: npm help | install | ls | search | ...
Packages can be installed locally
or globally via -g (useful to use packages as cmdline tools)
npm install <modname> will create a directory ./node_modules/
nvm (Node Version Manager)
Commands: nvm install | use | ls | run | ...
PCD1718 Introduction NodeJS in practice Async programming in Node 9/32
Modules and packages On JavaScript Examples
Outline
1 Introduction
2 NodeJS in practice
Modules and packages
On JavaScript
Examples
3 Async programming in Node
Promises
PCD1718 Introduction NodeJS in practice Async programming in Node 10/32
Modules and packages On JavaScript Examples
package.json
File package.json describes a Node package and its dependencies
npm init: guides you to the creation of a new package.json
Minimal example
{
"name": "my-node-project",
"version": "0.0.1"
}
Dependencies
{
"dependencies": { "cheerio": "1.0.0" },
"devDependencies": { ... } // for development & testing
}
npm install: installs local dependencies under ./node_modules
PCD1718 Introduction NodeJS in practice Async programming in Node 11/32
Modules and packages On JavaScript Examples
Modules and packages I
Module: basic definitions
A module is any file or directory that can be loaded by Node.js’ require()
A package is a file or directory described by a package.json
Module example
In the Node.js module system, each file is treated as a separate module
// mymodule.js
const anotherModule = require('anotherModule')
console.log(module);
In each module, the module free variable is a reference to the object
representing the current module.
PCD1718 Introduction NodeJS in practice Async programming in Node 12/32
Modules and packages On JavaScript Examples
Modules and packages II
Main module
When a file is run directly from Node.js, require.main is set to its module.
That means that it is possible to determine whether a file has been run directly by
testing require.main===module
For a file foo.js, this will be true if run via node foo.js, but false if run by
require('./foo')
Because module provides a filename property, the entry point of the current app
can be obtained by checking require.main.filename
Core modules
Core modules are compiled into Node binary distribution and loaded automatically
when Node process starts
Still, these need to be imported in order to be used it in your application.
Some core modules: http, url, querystring, path, fs, util
PCD1718 Introduction NodeJS in practice Async programming in Node 13/32
Modules and packages On JavaScript Examples
Modules and packages III
Exporting
// mymodule.js
exports.f = function(){ console.log('my module function' };
// anothermodule.js
mymod = require('mymodule') // NOTE: without .js
mymod.f()
The module.exports object in every module is what the require() function
returns when we require that module.
Caching: modules are cached after the first time they are loaded: so multiple
calls to require('foo') will get exactly the same object returned, and module
code will execute once.
Cycles: when there are circular require() calls, a module might not have
finished executing when it is returned.
PCD1718 Introduction NodeJS in practice Async programming in Node 14/32
Modules and packages On JavaScript Examples
Module resolution I
File modules: if moduleName starts with /, it’s considered an absolute path
and returned as it is. If starts by ./ then it is considered a relative path
calculated from the requiring module.
Core modules: if moduleName is not prefixed by / or ./, the algorithm will first
try to search within the core Node.js modules.
Package modules: if no core module matching moduleName is found, then the
search continues by looking for a matching module in the first node_modules dir
that is found navigating up in the directory structure starting from the requiring
module. The algorithm continues to search for a match by looking into the next
node_modules dir up in the dir tree, until it reaches the filesystem root.
For file and package modules, both the individual files and directories can
match moduleName:
<moduleName>.js
<moduleName>/index.js
The directory/file specified in the main property of <moduleName>/package.json
The node_modules dir is actually where npm installs the dependencies of each
package.
PCD1718 Introduction NodeJS in practice Async programming in Node 15/32
Modules and packages On JavaScript Examples
Module resolution II
This means that, based on this algorithm, each package can have its own
private dependencies.
myApp
|---- foo.js
|---- node_modules
|---- depA
| |---- index.js
|---- depB
| |---- bar.js
| |---- node_modules
| |---- depA
| |---- index.js
|---- depC
|---- foobar.js
!---- node_modules
|---- depA
|---- index.js
In example above, all the modules have their private version of depA.
PCD1718 Introduction NodeJS in practice Async programming in Node 16/32
Modules and packages On JavaScript Examples
Outline
1 Introduction
2 NodeJS in practice
Modules and packages
On JavaScript
Examples
3 Async programming in Node
Promises
PCD1718 Introduction NodeJS in practice Async programming in Node 17/32
Modules and packages On JavaScript Examples
JavaScript
Typing: dynamic, weak
Multi-paradigm: imperative, object-oriented, functional, event-driven
Standard: ECMAScript
– ES’2015 (ES6): classes, modules, generators, arrow functions, promises, ...
Originally implemented client-side in web browsers; not also server-side
ES6 support by Node versions: http://node.green/
PCD1718 Introduction NodeJS in practice Async programming in Node 18/32
Modules and packages On JavaScript Examples
Basics1
Influenced by: Java, C, Python, ...
5 primitive types: numbers, strings, , stringhe, booleani, Null, Undefined
var x = 10.7; // hoisted at global or function level
const y = "hello"; // block-level scoped
var arr = [1,2,3];
for(var i = 0; i < arr.length; i++)
console.log(arr[i]);
var obj = {
"prop1": true,
"method": function(){ this.prop1 = false; }
};
obj.method()
obj["method"]() // also
obj.prop1 // => false
function someConstructor(p){ this.prop = p; }
var instance = new someConstructor(77);
instance instanceof someConstructor // true
someConstructor.prototype.x = 99
instance.x // 99
1https://metaphori.github.io/ifts-2017-intro-programming-with-JS/
PCD1718 Introduction NodeJS in practice Async programming in Node 19/32
Modules and packages On JavaScript Examples
Outline
1 Introduction
2 NodeJS in practice
Modules and packages
On JavaScript
Examples
3 Async programming in Node
Promises
PCD1718 Introduction NodeJS in practice Async programming in Node 20/32
Modules and packages On JavaScript Examples
Webserver + filesystem functions
// webserver.js
var sys = require("sys"),
http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs");
http.createServer(function(request, response) {
var uri = url.parse(request.url).pathname;
var filename = path.join(process.cwd(), uri);
fs.access(filename, function(err) {
if(!err) {
fs.readFile(filename, function(err, data) {
response.writeHead(200);
response.end(data);
});
} else {
response.writeHead(404);
response.end('NOT FOUND');
}
});
}).listen(8080);
sys.log("Server running at http://localhost:8080/");PCD1718 Introduction NodeJS in practice Async programming in Node 21/32
Modules and packages On JavaScript Examples
HTTP requests
// requests.js
const request = require('request'), cheerio = require('cheerio');
if(process.argv.length < 3){
console.log("USE: requests.js <URL>"); process.exit(0);
}
const url = process.argv[2];
const MAX_REQUESTS = 3;
var k = 0;
function processLink(error, response, body) {
if(response && response.statusCode==200){
$ = cheerio.load(body);
var links = $('a').map((i,x) => $(x).attr('href')).get();
k = k + 1;
console.log(`Processing link ${k}: ${response.request.uri.href}`+
`n${JSON.stringify(links,null,4)}nn`)
if(k < MAX_REQUESTS && links.length){
request(links[Math.floor(Math.random()*links.length)], processLink);
} // Do you see any problems?
}
}
request(url, processLink);
PCD1718 Introduction NodeJS in practice Async programming in Node 22/32
Modules and packages On JavaScript Examples
Child processes
// fib.js
function fib(n){
if(n==0) return 0;
else if(n==1) return 1;
else return fib(n-2)+fib(n-1);
}
process.on('message',
msg => { process.send({event: 'data', k: msg, data: fib(msg)}); });
// index.js
const child_process = require('child_process');
const child = child_process.fork('fib.js');
var k = 0; const MAX = process.argv[2];
child.on('message', (msg) => {
console.log(`Message from child #${msg.k}: ${msg.data}`);
if(k<MAX){ k = k+1; child.send(k); }
else { child.disconnect(); }
});
child.send(k); // start
PCD1718 Introduction NodeJS in practice Async programming in Node 23/32
Promises
Outline
1 Introduction
2 NodeJS in practice
3 Async programming in Node
Promises
PCD1718 Introduction NodeJS in practice Async programming in Node 24/32
Promises
Outline
1 Introduction
2 NodeJS in practice
Modules and packages
On JavaScript
Examples
3 Async programming in Node
Promises
PCD1718 Introduction NodeJS in practice Async programming in Node 25/32
Promises
Promises: intro I
CPS is not the only way to write asynchronous code.
An alternative is promises
They’re part of ECMAScript 2015 (ES6) and available in Node since v4
The Promises/A+ specification for interoperability across libs
Promises/A+ impls: ES2015 promises, Bluebird, Q, RSVP, Vow, When.js..
A promise is an object representing the eventual result of an async task
States of a promise: pending – settled (fulfilled – rejected)
promise.then([onFulfilled], [onRejected]): to specify async
callbacks on promise fulfillment/rejection
// CPS-style
asyncOp(arg, (err, res) => {
if(err) { ... } // handle error
// do stuff with res
});
// PROMISE
asyncOp(arg)
.then(res => { ... },
err => { ... });
Calls to then() return another promise, allowing chaining of promises.
PCD1718 Introduction NodeJS in practice Async programming in Node 26/32
Promises
Promises: intro II
Unlike with CPS, throw statement can be used: this causes rejection and is
propagated across promise chains.
new Promise((res,rej) => setImmediate(()=>{ log("#1"); res(77); }))
.then(res => log("#2")).then(res => log("#3"));
new Promise((res,rej) => { console.log("#4"); res(88); })
.then(res => log("#5")).then(res => log("#6"));
log("#7"); // OUTPUT ORDER: #4 #7 #5 #6 #1 # 2 #3
// Using nextTick instead of setImmediate: #4 #7 #1 #5 #2 #6 #3
PCD1718 Introduction NodeJS in practice Async programming in Node 27/32
Promises
ES6 Promises API
new Promise(function(resolve, reject){}): creates a new promise that
fulfills or rejects based on the behavior of the provided function (immediately invoked)
resolve(obj): will resolve the promise with a fulfillment value or promise
reject(err): rejects the promise with reason err
Static method on Promise
Promise.resolve(obj): creates a new promise from a thenable or a value
Promise.reject(err): creates a promise that rejects with err as reason
Promise.all(iterable): creates a promise that fulfills with an iterable of
fulfillment values when every item (promise/thenable/value) in the iterable object
fulfills, or rejects with the first rejection
Promise.race(iterable): returns a promise fulfilled as soon as one of the
promises in the iterable is fulfilled, with the corresponding value
Methods on Promise instances
p.then(onFulfilled, onRejected)
p.catch(onRejected): sugar for promise.then(undefined,onRejected)
PCD1718 Introduction NodeJS in practice Async programming in Node 28/32
Promises
“Promisification”
Promisification: convert a typical callback-based function into one that returns
a promise
Example of a promisify helper function:
module.exports.promisify = function(callbackBasedApi) {
return function promisified() {
// [].slice.call(): converts array-like objs to real arrays
const args = [].slice.call(arguments);
return new Promise((resolve, reject) => {
args.push((err, result) => {
if(err) { return reject(err); }
if(arguments.length <= 2) {
resolve(result);
} else {
resolve([].slice.call(arguments, 1));
}
});
callbackBasedApi.apply(null, args);
});
}
};
// Use
const pReadFile = promisify(fs.readFile);
pReadFile('promises.js', 'utf-8').then(txt => console.log(txt));
PCD1718 Introduction NodeJS in practice Async programming in Node 29/32
Promises
Promises and asynchronous control flow patterns I
Pattern Sequential Execution with Promises
promisifiedFunction(...)
.then(x => ... )
.then(() => ... )
.catch(err => ...)
Pattern Sequential Iteration with Promises
let tasks = [ ... ]
let p = Promise.resolve(); // Empty promise, resolves to undefined
tasks.forEach(task => { p = p.then(() => task(); ); });
p.then(() => { ... }); // All tasks completed
// ALTERNATIVE: reduce instead of forEach
let promise = tasks.reduce((prev, task) => prev.then(() => task()),
Promise.resolve());
I.e., we dynamically build a chain of promises: at the end of the loop,
promise will contain the promise of the last then() invocation in the loop, so it
will resolve only when all the promises in the chain have been resolved.
PCD1718 Introduction NodeJS in practice Async programming in Node 30/32
Promises
Promises and asynchronous control flow patterns II
Pattern Parallel Execution with Promises
Promise.all(tasks.map(t => t()) // tasks are promisified functions
Start all tasks at once, collecting their promises; and then generate a promise
that will be fulfilled when all these promises are fulfilled (or rejected on first
reject).
PCD1718 Introduction NodeJS in practice Async programming in Node 31/32
References I
M. Casciaro. Node.js Design Patterns, 2nd Edition. Community Experience Distilled. Packt
Publishing, 2016. URL: https://books.google.it/books?id=Ys4GBgAAQBAJ.
Node documentation. https://nodejs.org/en/docs. [Online; accessed 04-2018].
Npm documentation. https://docs.npmjs.com/. [Online; accessed 04-2018].
PCD1718 Appendix References 32/32

NodeJS: an Introduction

  • 1.
    Node.js An introduction Roberto Casadei Concurrentand Distributed Programming course Department of Computer Science and Engineering (DISI) Alma Mater Studiorum – Università of Bologna June 16, 2018 PCD1718 Introduction NodeJS in practice Async programming in Node 1/32
  • 2.
    Outline 1 Introduction 2 NodeJSin practice 3 Async programming in Node PCD1718 Introduction NodeJS in practice Async programming in Node 2/32
  • 3.
    Node.js » intro Node.jsis a JS runtime environment that processes incoming events in a loop, called the event loop. Node.js provides an event-driven architecture and a non-blocking I/O API that optimizes an application’s throughput and scalability. This model is commonly used to design high-performance real-time web apps. Support any PL that can compile to JS (e.g., CoffeeScript, TypeScript) Builds on Google V8 JavaScript engine Node.js uses libuv to handle asynchronous events Libuv is an abstraction layer for network and file system functionality on both Windows and POSIX-based systems Libuv provides cross-platform asynchronous I/O Small core + rich userland of simple modules » NPM (Node Package Manager) PCD1718 Introduction NodeJS in practice Async programming in Node 3/32
  • 4.
    Node.js » systemoverview PCD1718 Introduction NodeJS in practice Async programming in Node 4/32
  • 5.
    Node.js » eventloop I The event loop is what allows Node.js to perform non-blocking I/O ops (despite the fact that JS is single-threaded) by offloading operations to the system kernel When one of these operations completes, the kernel tells Node.js so that the appropriate callback may be added to the poll queue to eventually be executed. When Node.js starts 1) Initializes the event loop 2) Processes the provided input script This may make async API calls, schedule timers, or call process.nextTick() 3) Begins processing the event loop Until no more events are available PCD1718 Introduction NodeJS in practice Async programming in Node 5/32
  • 6.
    Node.js » eventloop II Event loop structure Consists of phases. Each phase has a FIFO queue of callbacks to execute On a phase, Node.js runs any operations specific to that phase, then runs callbacks in that phase’s queue (until empty queue or max num of callbacks are executed), then moves to the next phase. Since any op may schedule more ops and new events processed in the poll phase are queued by the kernel, poll events can be queued while polling events are being processed. Between each run of the event loop, Node.js checks if it is waiting for any asynchronous I/O or timers and shuts down cleanly if there are not any. PCD1718 Introduction NodeJS in practice Async programming in Node 6/32
  • 7.
    Node.js » eventloop III Event loop phases timers: executes callbacks scheduled by setTimeout() and setInterval() A timer specifies the threshold after which a provided callback may be executed rather than the exact time a person wants it to be run. pending I/O callbacks: execs almost all callbacks with exception of close callbacks, the ones scheduled by timers, and setImmediate idle, prepare: only used internally poll: retrieve new I/O events; node will block here when appropriate Two main functions: 1) Executing scripts for timers whose threshold has elapsed, then 2) Processing events in the poll queue To prevent the poll phase from starving the event loop, libuv also has a hard maximum (system dependent) before it stops polling for more events. check: setImmediate callbacks are invoked here close callbacks: e.g., socket.on('close',...) See Node.js doc & libuv for more details. PCD1718 Introduction NodeJS in practice Async programming in Node 7/32
  • 8.
    Modules and packagesOn JavaScript Examples Outline 1 Introduction 2 NodeJS in practice Modules and packages On JavaScript Examples 3 Async programming in Node PCD1718 Introduction NodeJS in practice Async programming in Node 8/32
  • 9.
    Modules and packagesOn JavaScript Examples Node toolchain node node: starts REPL node <file.js>: runs given script npm (Node Package Manager) Automatically installed with node Commands: npm help | install | ls | search | ... Packages can be installed locally or globally via -g (useful to use packages as cmdline tools) npm install <modname> will create a directory ./node_modules/ nvm (Node Version Manager) Commands: nvm install | use | ls | run | ... PCD1718 Introduction NodeJS in practice Async programming in Node 9/32
  • 10.
    Modules and packagesOn JavaScript Examples Outline 1 Introduction 2 NodeJS in practice Modules and packages On JavaScript Examples 3 Async programming in Node Promises PCD1718 Introduction NodeJS in practice Async programming in Node 10/32
  • 11.
    Modules and packagesOn JavaScript Examples package.json File package.json describes a Node package and its dependencies npm init: guides you to the creation of a new package.json Minimal example { "name": "my-node-project", "version": "0.0.1" } Dependencies { "dependencies": { "cheerio": "1.0.0" }, "devDependencies": { ... } // for development & testing } npm install: installs local dependencies under ./node_modules PCD1718 Introduction NodeJS in practice Async programming in Node 11/32
  • 12.
    Modules and packagesOn JavaScript Examples Modules and packages I Module: basic definitions A module is any file or directory that can be loaded by Node.js’ require() A package is a file or directory described by a package.json Module example In the Node.js module system, each file is treated as a separate module // mymodule.js const anotherModule = require('anotherModule') console.log(module); In each module, the module free variable is a reference to the object representing the current module. PCD1718 Introduction NodeJS in practice Async programming in Node 12/32
  • 13.
    Modules and packagesOn JavaScript Examples Modules and packages II Main module When a file is run directly from Node.js, require.main is set to its module. That means that it is possible to determine whether a file has been run directly by testing require.main===module For a file foo.js, this will be true if run via node foo.js, but false if run by require('./foo') Because module provides a filename property, the entry point of the current app can be obtained by checking require.main.filename Core modules Core modules are compiled into Node binary distribution and loaded automatically when Node process starts Still, these need to be imported in order to be used it in your application. Some core modules: http, url, querystring, path, fs, util PCD1718 Introduction NodeJS in practice Async programming in Node 13/32
  • 14.
    Modules and packagesOn JavaScript Examples Modules and packages III Exporting // mymodule.js exports.f = function(){ console.log('my module function' }; // anothermodule.js mymod = require('mymodule') // NOTE: without .js mymod.f() The module.exports object in every module is what the require() function returns when we require that module. Caching: modules are cached after the first time they are loaded: so multiple calls to require('foo') will get exactly the same object returned, and module code will execute once. Cycles: when there are circular require() calls, a module might not have finished executing when it is returned. PCD1718 Introduction NodeJS in practice Async programming in Node 14/32
  • 15.
    Modules and packagesOn JavaScript Examples Module resolution I File modules: if moduleName starts with /, it’s considered an absolute path and returned as it is. If starts by ./ then it is considered a relative path calculated from the requiring module. Core modules: if moduleName is not prefixed by / or ./, the algorithm will first try to search within the core Node.js modules. Package modules: if no core module matching moduleName is found, then the search continues by looking for a matching module in the first node_modules dir that is found navigating up in the directory structure starting from the requiring module. The algorithm continues to search for a match by looking into the next node_modules dir up in the dir tree, until it reaches the filesystem root. For file and package modules, both the individual files and directories can match moduleName: <moduleName>.js <moduleName>/index.js The directory/file specified in the main property of <moduleName>/package.json The node_modules dir is actually where npm installs the dependencies of each package. PCD1718 Introduction NodeJS in practice Async programming in Node 15/32
  • 16.
    Modules and packagesOn JavaScript Examples Module resolution II This means that, based on this algorithm, each package can have its own private dependencies. myApp |---- foo.js |---- node_modules |---- depA | |---- index.js |---- depB | |---- bar.js | |---- node_modules | |---- depA | |---- index.js |---- depC |---- foobar.js !---- node_modules |---- depA |---- index.js In example above, all the modules have their private version of depA. PCD1718 Introduction NodeJS in practice Async programming in Node 16/32
  • 17.
    Modules and packagesOn JavaScript Examples Outline 1 Introduction 2 NodeJS in practice Modules and packages On JavaScript Examples 3 Async programming in Node Promises PCD1718 Introduction NodeJS in practice Async programming in Node 17/32
  • 18.
    Modules and packagesOn JavaScript Examples JavaScript Typing: dynamic, weak Multi-paradigm: imperative, object-oriented, functional, event-driven Standard: ECMAScript – ES’2015 (ES6): classes, modules, generators, arrow functions, promises, ... Originally implemented client-side in web browsers; not also server-side ES6 support by Node versions: http://node.green/ PCD1718 Introduction NodeJS in practice Async programming in Node 18/32
  • 19.
    Modules and packagesOn JavaScript Examples Basics1 Influenced by: Java, C, Python, ... 5 primitive types: numbers, strings, , stringhe, booleani, Null, Undefined var x = 10.7; // hoisted at global or function level const y = "hello"; // block-level scoped var arr = [1,2,3]; for(var i = 0; i < arr.length; i++) console.log(arr[i]); var obj = { "prop1": true, "method": function(){ this.prop1 = false; } }; obj.method() obj["method"]() // also obj.prop1 // => false function someConstructor(p){ this.prop = p; } var instance = new someConstructor(77); instance instanceof someConstructor // true someConstructor.prototype.x = 99 instance.x // 99 1https://metaphori.github.io/ifts-2017-intro-programming-with-JS/ PCD1718 Introduction NodeJS in practice Async programming in Node 19/32
  • 20.
    Modules and packagesOn JavaScript Examples Outline 1 Introduction 2 NodeJS in practice Modules and packages On JavaScript Examples 3 Async programming in Node Promises PCD1718 Introduction NodeJS in practice Async programming in Node 20/32
  • 21.
    Modules and packagesOn JavaScript Examples Webserver + filesystem functions // webserver.js var sys = require("sys"), http = require("http"), url = require("url"), path = require("path"), fs = require("fs"); http.createServer(function(request, response) { var uri = url.parse(request.url).pathname; var filename = path.join(process.cwd(), uri); fs.access(filename, function(err) { if(!err) { fs.readFile(filename, function(err, data) { response.writeHead(200); response.end(data); }); } else { response.writeHead(404); response.end('NOT FOUND'); } }); }).listen(8080); sys.log("Server running at http://localhost:8080/");PCD1718 Introduction NodeJS in practice Async programming in Node 21/32
  • 22.
    Modules and packagesOn JavaScript Examples HTTP requests // requests.js const request = require('request'), cheerio = require('cheerio'); if(process.argv.length < 3){ console.log("USE: requests.js <URL>"); process.exit(0); } const url = process.argv[2]; const MAX_REQUESTS = 3; var k = 0; function processLink(error, response, body) { if(response && response.statusCode==200){ $ = cheerio.load(body); var links = $('a').map((i,x) => $(x).attr('href')).get(); k = k + 1; console.log(`Processing link ${k}: ${response.request.uri.href}`+ `n${JSON.stringify(links,null,4)}nn`) if(k < MAX_REQUESTS && links.length){ request(links[Math.floor(Math.random()*links.length)], processLink); } // Do you see any problems? } } request(url, processLink); PCD1718 Introduction NodeJS in practice Async programming in Node 22/32
  • 23.
    Modules and packagesOn JavaScript Examples Child processes // fib.js function fib(n){ if(n==0) return 0; else if(n==1) return 1; else return fib(n-2)+fib(n-1); } process.on('message', msg => { process.send({event: 'data', k: msg, data: fib(msg)}); }); // index.js const child_process = require('child_process'); const child = child_process.fork('fib.js'); var k = 0; const MAX = process.argv[2]; child.on('message', (msg) => { console.log(`Message from child #${msg.k}: ${msg.data}`); if(k<MAX){ k = k+1; child.send(k); } else { child.disconnect(); } }); child.send(k); // start PCD1718 Introduction NodeJS in practice Async programming in Node 23/32
  • 24.
    Promises Outline 1 Introduction 2 NodeJSin practice 3 Async programming in Node Promises PCD1718 Introduction NodeJS in practice Async programming in Node 24/32
  • 25.
    Promises Outline 1 Introduction 2 NodeJSin practice Modules and packages On JavaScript Examples 3 Async programming in Node Promises PCD1718 Introduction NodeJS in practice Async programming in Node 25/32
  • 26.
    Promises Promises: intro I CPSis not the only way to write asynchronous code. An alternative is promises They’re part of ECMAScript 2015 (ES6) and available in Node since v4 The Promises/A+ specification for interoperability across libs Promises/A+ impls: ES2015 promises, Bluebird, Q, RSVP, Vow, When.js.. A promise is an object representing the eventual result of an async task States of a promise: pending – settled (fulfilled – rejected) promise.then([onFulfilled], [onRejected]): to specify async callbacks on promise fulfillment/rejection // CPS-style asyncOp(arg, (err, res) => { if(err) { ... } // handle error // do stuff with res }); // PROMISE asyncOp(arg) .then(res => { ... }, err => { ... }); Calls to then() return another promise, allowing chaining of promises. PCD1718 Introduction NodeJS in practice Async programming in Node 26/32
  • 27.
    Promises Promises: intro II Unlikewith CPS, throw statement can be used: this causes rejection and is propagated across promise chains. new Promise((res,rej) => setImmediate(()=>{ log("#1"); res(77); })) .then(res => log("#2")).then(res => log("#3")); new Promise((res,rej) => { console.log("#4"); res(88); }) .then(res => log("#5")).then(res => log("#6")); log("#7"); // OUTPUT ORDER: #4 #7 #5 #6 #1 # 2 #3 // Using nextTick instead of setImmediate: #4 #7 #1 #5 #2 #6 #3 PCD1718 Introduction NodeJS in practice Async programming in Node 27/32
  • 28.
    Promises ES6 Promises API newPromise(function(resolve, reject){}): creates a new promise that fulfills or rejects based on the behavior of the provided function (immediately invoked) resolve(obj): will resolve the promise with a fulfillment value or promise reject(err): rejects the promise with reason err Static method on Promise Promise.resolve(obj): creates a new promise from a thenable or a value Promise.reject(err): creates a promise that rejects with err as reason Promise.all(iterable): creates a promise that fulfills with an iterable of fulfillment values when every item (promise/thenable/value) in the iterable object fulfills, or rejects with the first rejection Promise.race(iterable): returns a promise fulfilled as soon as one of the promises in the iterable is fulfilled, with the corresponding value Methods on Promise instances p.then(onFulfilled, onRejected) p.catch(onRejected): sugar for promise.then(undefined,onRejected) PCD1718 Introduction NodeJS in practice Async programming in Node 28/32
  • 29.
    Promises “Promisification” Promisification: convert atypical callback-based function into one that returns a promise Example of a promisify helper function: module.exports.promisify = function(callbackBasedApi) { return function promisified() { // [].slice.call(): converts array-like objs to real arrays const args = [].slice.call(arguments); return new Promise((resolve, reject) => { args.push((err, result) => { if(err) { return reject(err); } if(arguments.length <= 2) { resolve(result); } else { resolve([].slice.call(arguments, 1)); } }); callbackBasedApi.apply(null, args); }); } }; // Use const pReadFile = promisify(fs.readFile); pReadFile('promises.js', 'utf-8').then(txt => console.log(txt)); PCD1718 Introduction NodeJS in practice Async programming in Node 29/32
  • 30.
    Promises Promises and asynchronouscontrol flow patterns I Pattern Sequential Execution with Promises promisifiedFunction(...) .then(x => ... ) .then(() => ... ) .catch(err => ...) Pattern Sequential Iteration with Promises let tasks = [ ... ] let p = Promise.resolve(); // Empty promise, resolves to undefined tasks.forEach(task => { p = p.then(() => task(); ); }); p.then(() => { ... }); // All tasks completed // ALTERNATIVE: reduce instead of forEach let promise = tasks.reduce((prev, task) => prev.then(() => task()), Promise.resolve()); I.e., we dynamically build a chain of promises: at the end of the loop, promise will contain the promise of the last then() invocation in the loop, so it will resolve only when all the promises in the chain have been resolved. PCD1718 Introduction NodeJS in practice Async programming in Node 30/32
  • 31.
    Promises Promises and asynchronouscontrol flow patterns II Pattern Parallel Execution with Promises Promise.all(tasks.map(t => t()) // tasks are promisified functions Start all tasks at once, collecting their promises; and then generate a promise that will be fulfilled when all these promises are fulfilled (or rejected on first reject). PCD1718 Introduction NodeJS in practice Async programming in Node 31/32
  • 32.
    References I M. Casciaro.Node.js Design Patterns, 2nd Edition. Community Experience Distilled. Packt Publishing, 2016. URL: https://books.google.it/books?id=Ys4GBgAAQBAJ. Node documentation. https://nodejs.org/en/docs. [Online; accessed 04-2018]. Npm documentation. https://docs.npmjs.com/. [Online; accessed 04-2018]. PCD1718 Appendix References 32/32