Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
YOU DON'T
KNOW NODE
QUICK INTRO TO 6 CORE
FEATURES1 — © Capital One, 2016
BETTER APPS—
BETTER LIFE
2 — © Capital One, 2016
ABOUT PRESENTER
Azat Mardan
Twitter: @azat_co
Email: hi@azat.co
Blog: webapplog.com
3 — © Capital One, 2016
ABOUT PRESENTER
> Work: Technology Fellow at Capital One
> Experience: FDIC, NIH, DocuSign, HackReactor and Storify
> Book...
5 — © Capital One, 2016
STARTING WITH
BASICS: WHY
USE NODE?6 — © Capital One, 2016
WAIT FOR
INPUT/OUTPUT
WHICH ARE THE
MOST7 — © Capital One, 2016
JAVA SLEEP
System.out.println("Step: 1");
System.out.println("Step: 2");
Thread.sleep(1000);
System.out.println("Step: 3")...
9 — © Capital One, 2016
NODE "SLEEP"
console.log('Step: 1')
setTimeout(function () {
console.log('Step: 3')
}, 1000)
console.log('Step: 2')
10 — ©...
PROCESS MULTIPLE TASKS
console.log('Step: 1')
setTimeout(function () {
console.log('Step: 3')
// console.log('Step 5')
}, ...
EVENT LOOP
12 — © Capital One, 2016
13 — © Capital One, 2016
[MUTLI-THREADING] IS THE SOFTWARE
EQUIVALENT OF A NUCLEAR DEVICE
BECAUSE IF IT IS USED INCORRECTLY, IT
CAN BLOW UP IN YOUR...
SINGLE THREAD
- NO WORRIES
!15 — © Capital One, 2016
16 — © Capital One, 2016
IT'S STILL POSSIBLE TO
WRITE BLOCKING CODE IN
NODE.JS. !
17 — © Capital One, 2016
BLOCKING NODE.JS CODE
// blocking.js
console.log('Step: 1')
for (var i = 1; i<1000000000; i++) {
// This will take 100-100...
BLOCKING NODE.JS CODE
var fs = require('fs')
var contents = fs.readFileSync('accounts.txt','utf8')
console.log(contents)
c...
NON-BLOCKING NODE.JS CODE
var fs = require('fs')
var contents = fs.readFile('accounts.txt','utf8', function(err,contents){...
MOST OF NODE IS JAVASCRIPT
> Array
> String
> Primitives
> Functions
> Objects
21 — © Capital One, 2016
NODE !=
BROWSER
JAVASCRIPT22 — © Capital One, 2016
HOW TO CREATE GLOBAL VARIABLES
(NO window IN NODE)?
23 — © Capital One, 2016
GLOBAL
24 — © Capital One, 2016
global.__fi
lename
25 — © Capital One, 2016
global.__di
rname
26 — © Capital One, 2016
global.modu
le
27 — © Capital One, 2016
global.requ
ire()
28 — © Capital One, 2016
global.proc
ess
29 — © Capital One, 2016
> How to access CLI input, OS, platform, memory usage,
versions, etc.?
> Where to store passwords?
30 — © Capital One, 2016
PROCESS
31 — © Capital One, 2016
process.pid
32 — © Capital One, 2016
process.ver
sions
33 — © Capital One, 2016
process.arc
h
34 — © Capital One, 2016
process.arg
v
35 — © Capital One, 2016
process.env
36 — © Capital One, 2016
process.upt
ime()
37 — © Capital One, 2016
process.mem
oryUsage()
38 — © Capital One, 2016
process.cwd
()
39 — © Capital One, 2016
process.exi
t()
40 — © Capital One, 2016
process.on(
)
41 — © Capital One, 2016
WHO LIKES AND
UNDERSTANDS
CALLBACKS?
!42 — © Capital One, 2016
http://callbackhell.com
fs.readdir(source, function (err, files) {
if (err) {
console.log('Error finding files: ' + err)
}...
CALLBACKS ARE NOT
VERY DEVELOPMENTAL
SCALABLE !
44 — © Capital One, 2016
ME WHEN WORKING WITH DEEPLY NESTED
CALLBACKS
45 — © Capital One, 2016
EVENTS
46 — © Capital One, 2016
EVENTS
In node.js an event can be described simply as a string
with a corresponding callback.
emitter.on('done', function(...
EVENT HANDLING IN NODE USES THE
OBSERVER PATTERN
48 — © Capital One, 2016
AN EVENT, OR SUBJECT, KEEPS TRACK
OF ALL FUNCTIONS THAT ARE
ASSOCIATED WITH IT
49 — © Capital One, 2016
THESE ASSOCIATED FUNCTIONS, KNOWN
AS OBSERVERS, ARE EXECUTED WHEN
THE GIVEN EVENT IS TRIGGERED
50 — © Capital One, 2016
USING EVENT EMITTERS
var events = require('events')
var emitter = new events.EventEmitter()
emitter.on('knock', function()...
INHERITING FROM EVENTEMITTER
// job.js
var util = require('util')
var Job = function Job() {
// ...
this.process = functio...
INHERITING FROM EVENTEMITTER
// weekly.js
var Job = require('./job.js')
var job = new Job()
job.on('done', function(detail...
LISTENERS
emitter.listeners(eventName)
emitter.on(eventName, listener)
emitter.once(eventName, listener)
emitter.removeLis...
PROBLEMS WITH LARGE DATA
> Speed: Too slow
> Buffer limit: ~1Gb
55 — © Capital One, 2016
STREAMS
ABSTACTIONS FOR
CONTINUOS CHUNKING OF
DATA
56 — © Capital One, 2016
NO NEED TO
WAIT FOR THE
ENTIRE
RESOURCE TO57 — © Capital One, 2016
TYPES OF STREAMS
> Readable
> Writable
> Duplex
> Transform
58 — © Capital One, 2016
STREAMS INHERIT FROM
EVENT EMITTER
59 — © Capital One, 2016
STREAMS ARE EVERYWHERE!
> HTTP requests and responses
> Standard input/output (stdin&stdout)
> File reads and writes
60 — ...
READABLE STREAM EXAMPLE
process.stdin
Standard input streams contain data going into
applications.
61 — © Capital One, 2016
THIS IS
ACHIEVED VIA A
READ
OPERATION.62 — © Capital One, 2016
TYPICALLY
COMES FROM
THE KEYBOARD
USED TO START63 — © Capital One, 2016
To listen in on data from stdin, use the data and end
events:
// stdin.js
process.stdin.resume()
process.stdin.setEncoding...
DEMO
$ node stdin.js
65 — © Capital One, 2016
NEW INTERFACE read()
var readable = getReadableStreamSomehow()
readable.on('readable', () => {
var chunk
while (null !== (...
WRITABLE STREAM EXAMPLE
process.stdout
Standard output streams contain data going out of the
applications.
67 — © Capital ...
THIS IS DONE
VIA A WRITE
OPERATION.68 — © Capital One, 2016
DATA WRITTEN
TO STANDARD
OUTPUT IS
VISIBLE ON THE69 — © Capital One, 2016
WRITABLE STREAM
To write to stdout, use the write function:
process.stdout.write('A simple messagen')
70 — © Capital One, ...
WHAT ABOUT
HTTP?
71 — © Capital One, 2016
const http = require('http')
var server = http.createServer( (req, res) => {
var body = ''
req.setEncoding('utf8')
req.on(...
PIPE
var r = fs.createReadStream('file.txt')
var z = zlib.createGzip()
var w = fs.createWriteStream('file.txt.gz')
r.pipe(...
WHAT DATA TYPE TO USE
FOR BINARY DATA?
74 — © Capital One, 2016
BUFFERS
Binary data type, to create:
> new Buffer(size)
> new Buffer(array)
> new Buffer(buffer)
> new Buffer(str[, encodi...
WORKING WITH BUFFER
// buf.js
var buf = new Buffer(26)
for (var i = 0 ; i < 26 ; i++) {
buf[i] = i + 97 // 97 is ASCII a
}...
BUFFER CONVERTION
buf.toString('ascii') // outputs: abcdefghijklmnopqrstuvwxyz
buf.toString('ascii', 0, 5) // outputs: abc...
REMEMBER FS?
fs.readFile('/etc/passwd', function (err, data) {
if (err) return console.error(err)
console.log(data)
});
da...
DEMO
$ node server-stream
79 — © Capital One, 2016
STREAMS AND BUFFER DEMO
// server-stream.js
app.get('/stream', function(req, res) {
var stream = fs.createReadStream(large...
RESULTS IN DEVTOOLS
/stream responds faster!
X-Response-Time
~300ms vs. 3-5s
81 — © Capital One, 2016
STREAM RESOURCES
https://github.com/substack/stream-adventure
$ sudo npm install -g stream-adventure
$ stream-adventure
ht...
HOW TO SCALE
A SINGLE
THREADED
SYSTEM?83 — © Capital One, 2016
CLUSTER USAGE
> Master: starts workers
> Worker: do the job, e.g., HTTP server
Number of processes = number of CPUs
84 — ©...
CLUSTERS
var cluster = require('cluster')
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork()
}
} e...
CLUSTER DEMO
1. Run code/cluster.js with node ($ node
cluster.js).
2. Install loadtest with npm: $ npm install -g
loadtest...
CLUSTER LIBRARIES
> Core cluster: lean and mean
> strong-cluster-control (https://github.com/
strongloop/strong-cluster-co...
PM2
https://github.com/Unitech/pm2
http://pm2.keymetrics.io
Advantages:
> Load-balancer and other features
> 0s reload dow...
PM2 DEMO: TYPICAL EXPRESS SERVER
var express = require('express')
var port = 3000
global.stats = {}
console.log('worker (%...
PM2 DEMO
Using server.js:
$ pm2 start server.js -i 0
In a new window:
$ loadtest http://localhost:3000 -t 20 -c 10
$ pm2 l...
SPAWN VS FORK VS EXEC
> require('child_process').spawn() - large data,
stream, no new V8 instance
> require('child_process...
SPAWN EXAMPLE
fs = require('fs')
process = require('child_process')
var p = process.spawn('node', 'program.js')
p.stdout.o...
FORK EXAMPLE
fs = require('fs')
process = require('child_process')
var p = process.fork('program.js')
p.stdout.on('data', ...
EXEC EXAMPLE
fs = require('fs')
process = require('child_process')
var p = process.exec('node program.js', function (error...
HOW TO HANDLE
ASYNC ERRORS?
95 — © Capital One, 2016
HANDLING ASYNC ERRORS
Event Loop: Async errors are harder to handle/debug,
because system loses context of the error. Then...
SYNCHRONOUS ERROR IN NODE
try {
throw new Error('Fail!')
} catch (e) {
console.log('Custom Error: ' + e.message)
}
For syn...
ASYNC ERROR EXAMPLE
try {
setTimeout(function () {
throw new Error('Fail!')
}, Math.round(Math.random()*100))
} catch (e) ...
ME WHEN ASYNC ERROR'S THROWN
99 — © Capital One, 2016
ASYNC ERRORS
How to deal with it?
!
100 — © Capital One, 2016
BEST PRACTICES FOR ASYNC ERRORS?
> Listen to all “on error” events
> Listen to uncaughtException
> Use domain (soft deprec...
ON('ERROR')
Anything that inherits from or creates an instance of the
above: Express, LoopBack, Sails, Hapi, etc.
server.o...
ON('ERROR') CHAINED METHOD EXAMPLE
var http = require(‘http’)
var server = http.createServer(app)
.on('error', function(e)...
ON(‘ERROR’) NAMED VARIABLE EXAMPLE
var req = http.request(options, function(res) {
// … processing the response
})
req.on(...
UNCAUGHTEXCEPTION
uncaughtException is a very crude mechanism for
exception handling. An unhandled exception means your
ap...
UNCAUGHTEXCEPTION
Always listen to uncaughtException!
process.on(‘uncaughtException’, handle)
or
process.addListener('unca...
UNCAUGHTEXCEPTION EXPANDED EXAMPLES
process.on('uncaughtException', function (err) {
console.error('uncaughtException: ', ...
DOMAIN
This module is softly deprecated in 4.0 (most likey will be
separate from core module), but there's no alternatives...
DOMAIN EXAMPLE
var domain = require('domain').create()
domain.on('error', function(error){
console.log(error)
})
domain.ru...
DOMAIN WITH ASYNC ERROR DEMO
domain-async.js:
var d = require('domain').create()
d.on('error', function(e) {
console.log('...
C++ ADDONS
111 — © Capital One, 2016
HOW TO WRITE C/C++
BINDING FOR YOUR IOT,
HARDWARE, DRONE,
SMARTDEVICE, ETC.?
112 — © Capital One, 2016
NODE AND C++
Create the hello.cc file:
#include <node.h>
namespace demo {
using v8::FunctionCallbackInfo;
using v8::Handle...
NODE AND C++
Create the hello.cc file:
void Method(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetI...
CREATING binding.gyp
Create binding.gyp:
{
"targets": [
{
"target_name": "addon",
"sources": [ "hello.cc" ]
}
]
}
115 — © ...
NODE-GYP
$ npm install -g node-gyp
https://github.com/nodejs/node-gyp
116 — © Capital One, 2016
CONFIGURING AND BUILDING
$ node-gyp configure
$ node-gyp build
Check for compiled .node files in build/Release/
117 — © Ca...
C++ ADDONS EXAMPLES
https://github.com/nodejs/node-addon-examples
118 — © Capital One, 2016
INCLUDING ADDON
Create hello.js and include your C++ addon:
var addon = require('./build/Release/addon')
console.log(addon...
CAPITAL ONE
We use Node a lot!
https://www.youtube.com/watch?v=BJPeLJhv1Ic
120 — © Capital One, 2016
30-SECOND SUMMARY
1. Event Emitters
2. Streams
3. Buffers
4. Clusters
5. C++ Addons
6. Domain
121 — © Capital One, 2016
THE END
122 — © Capital One, 2016
SLIDES & CODE !
https://github.com/azat-co/you-dont-know-node
or
PDF: http://bit.ly/1VJWpQK
123 — © Capital One, 2016
Q&A ❓"➡$
Twitter: @azat_co
Email: hi@azat.co
124 — © Capital One, 2016
Upcoming SlideShare
Loading in …5
×

You Don't Know Node: Quick Intro to 6 Core Features

210 views

Published on

Azat Mardan
Technology Fellow
Capital One

Great Wide Open 2016
Atlanta, GA
March 16th, 2016

Published in: Technology
  • Be the first to comment

You Don't Know Node: Quick Intro to 6 Core Features

  1. 1. YOU DON'T KNOW NODE QUICK INTRO TO 6 CORE FEATURES1 — © Capital One, 2016
  2. 2. BETTER APPS— BETTER LIFE 2 — © Capital One, 2016
  3. 3. ABOUT PRESENTER Azat Mardan Twitter: @azat_co Email: hi@azat.co Blog: webapplog.com 3 — © Capital One, 2016
  4. 4. ABOUT PRESENTER > Work: Technology Fellow at Capital One > Experience: FDIC, NIH, DocuSign, HackReactor and Storify > Books: React Quickly, Practical Node.js, Pro Express.js, Express.js API and 8 others > Teach: NodeProgram.com 4 — © Capital One, 2016
  5. 5. 5 — © Capital One, 2016
  6. 6. STARTING WITH BASICS: WHY USE NODE?6 — © Capital One, 2016
  7. 7. WAIT FOR INPUT/OUTPUT WHICH ARE THE MOST7 — © Capital One, 2016
  8. 8. JAVA SLEEP System.out.println("Step: 1"); System.out.println("Step: 2"); Thread.sleep(1000); System.out.println("Step: 3"); 8 — © Capital One, 2016
  9. 9. 9 — © Capital One, 2016
  10. 10. NODE "SLEEP" console.log('Step: 1') setTimeout(function () { console.log('Step: 3') }, 1000) console.log('Step: 2') 10 — © Capital One, 2016
  11. 11. PROCESS MULTIPLE TASKS console.log('Step: 1') setTimeout(function () { console.log('Step: 3') // console.log('Step 5') }, 1000); console.log('Step: 2') // console.log('Step 4') 11 — © Capital One, 2016
  12. 12. EVENT LOOP 12 — © Capital One, 2016
  13. 13. 13 — © Capital One, 2016
  14. 14. [MUTLI-THREADING] IS THE SOFTWARE EQUIVALENT OF A NUCLEAR DEVICE BECAUSE IF IT IS USED INCORRECTLY, IT CAN BLOW UP IN YOUR FACE. http://blog.codinghorror.com/threading-concurrency- and-the-most-powerful-psychokinetic-explosive-in-the- univ 14 — © Capital One, 2016
  15. 15. SINGLE THREAD - NO WORRIES !15 — © Capital One, 2016
  16. 16. 16 — © Capital One, 2016
  17. 17. IT'S STILL POSSIBLE TO WRITE BLOCKING CODE IN NODE.JS. ! 17 — © Capital One, 2016
  18. 18. BLOCKING NODE.JS CODE // blocking.js console.log('Step: 1') for (var i = 1; i<1000000000; i++) { // This will take 100-1000ms } console.log('Step: 2') 18 — © Capital One, 2016
  19. 19. BLOCKING NODE.JS CODE var fs = require('fs') var contents = fs.readFileSync('accounts.txt','utf8') console.log(contents) console.log('Hello Rubyn') var contents = fs.readFileSync('ips.txt','utf8') console.log(contents) console.log('Hello Node!') //data1->Hello Ruby->data2->Hello NODE! 19 — © Capital One, 2016
  20. 20. NON-BLOCKING NODE.JS CODE var fs = require('fs') var contents = fs.readFile('accounts.txt','utf8', function(err,contents){ console.log(contents) }) console.log('Hello Pythonn') var contents = fs.readFile('ips.txt','utf8', function(err,contents){ console.log(contents) }) console.log("Hello Node!") //Hello Python->Hello Node->data1->data2 20 — © Capital One, 2016
  21. 21. MOST OF NODE IS JAVASCRIPT > Array > String > Primitives > Functions > Objects 21 — © Capital One, 2016
  22. 22. NODE != BROWSER JAVASCRIPT22 — © Capital One, 2016
  23. 23. HOW TO CREATE GLOBAL VARIABLES (NO window IN NODE)? 23 — © Capital One, 2016
  24. 24. GLOBAL 24 — © Capital One, 2016
  25. 25. global.__fi lename 25 — © Capital One, 2016
  26. 26. global.__di rname 26 — © Capital One, 2016
  27. 27. global.modu le 27 — © Capital One, 2016
  28. 28. global.requ ire() 28 — © Capital One, 2016
  29. 29. global.proc ess 29 — © Capital One, 2016
  30. 30. > How to access CLI input, OS, platform, memory usage, versions, etc.? > Where to store passwords? 30 — © Capital One, 2016
  31. 31. PROCESS 31 — © Capital One, 2016
  32. 32. process.pid 32 — © Capital One, 2016
  33. 33. process.ver sions 33 — © Capital One, 2016
  34. 34. process.arc h 34 — © Capital One, 2016
  35. 35. process.arg v 35 — © Capital One, 2016
  36. 36. process.env 36 — © Capital One, 2016
  37. 37. process.upt ime() 37 — © Capital One, 2016
  38. 38. process.mem oryUsage() 38 — © Capital One, 2016
  39. 39. process.cwd () 39 — © Capital One, 2016
  40. 40. process.exi t() 40 — © Capital One, 2016
  41. 41. process.on( ) 41 — © Capital One, 2016
  42. 42. WHO LIKES AND UNDERSTANDS CALLBACKS? !42 — © Capital One, 2016
  43. 43. http://callbackhell.com fs.readdir(source, function (err, files) { if (err) { console.log('Error finding files: ' + err) } else { files.forEach(function (filename, fileIndex) { console.log(filename) gm(source + filename).size(function (err, values) { if (err) { console.log('Error identifying file size: ' + err) } else { console.log(filename + ' : ' + values) aspect = (values.width / values.height) widths.forEach(function (width, widthIndex) { height = Math.round(width / aspect) console.log('resizing ' + filename + 'to ' + height + 'x' + height) this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) { if (err) console.log('Error writing file: ' + err) }) }.bind(this)) } }) }) } }) 43 — © Capital One, 2016
  44. 44. CALLBACKS ARE NOT VERY DEVELOPMENTAL SCALABLE ! 44 — © Capital One, 2016
  45. 45. ME WHEN WORKING WITH DEEPLY NESTED CALLBACKS 45 — © Capital One, 2016
  46. 46. EVENTS 46 — © Capital One, 2016
  47. 47. EVENTS In node.js an event can be described simply as a string with a corresponding callback. emitter.on('done', function(results) { console.log('Done: ', results) }) 47 — © Capital One, 2016
  48. 48. EVENT HANDLING IN NODE USES THE OBSERVER PATTERN 48 — © Capital One, 2016
  49. 49. AN EVENT, OR SUBJECT, KEEPS TRACK OF ALL FUNCTIONS THAT ARE ASSOCIATED WITH IT 49 — © Capital One, 2016
  50. 50. THESE ASSOCIATED FUNCTIONS, KNOWN AS OBSERVERS, ARE EXECUTED WHEN THE GIVEN EVENT IS TRIGGERED 50 — © Capital One, 2016
  51. 51. USING EVENT EMITTERS var events = require('events') var emitter = new events.EventEmitter() emitter.on('knock', function() { console.log('Who's there?') }) emitter.on('knock', function() { console.log('Go away!') }) emitter.emit('knock') 51 — © Capital One, 2016
  52. 52. INHERITING FROM EVENTEMITTER // job.js var util = require('util') var Job = function Job() { // ... this.process = function() { // ... job.emit('done', { completedOn: new Date() }) } } util.inherits(Job, require('events').EventEmitter) module.exports = Job 52 — © Capital One, 2016
  53. 53. INHERITING FROM EVENTEMITTER // weekly.js var Job = require('./job.js') var job = new Job() job.on('done', function(details){ console.log('Job was completed at', details.completedOn) job.removeAllListeners() }) job.process() 53 — © Capital One, 2016
  54. 54. LISTENERS emitter.listeners(eventName) emitter.on(eventName, listener) emitter.once(eventName, listener) emitter.removeListener(eventName, listener) 54 — © Capital One, 2016
  55. 55. PROBLEMS WITH LARGE DATA > Speed: Too slow > Buffer limit: ~1Gb 55 — © Capital One, 2016
  56. 56. STREAMS ABSTACTIONS FOR CONTINUOS CHUNKING OF DATA 56 — © Capital One, 2016
  57. 57. NO NEED TO WAIT FOR THE ENTIRE RESOURCE TO57 — © Capital One, 2016
  58. 58. TYPES OF STREAMS > Readable > Writable > Duplex > Transform 58 — © Capital One, 2016
  59. 59. STREAMS INHERIT FROM EVENT EMITTER 59 — © Capital One, 2016
  60. 60. STREAMS ARE EVERYWHERE! > HTTP requests and responses > Standard input/output (stdin&stdout) > File reads and writes 60 — © Capital One, 2016
  61. 61. READABLE STREAM EXAMPLE process.stdin Standard input streams contain data going into applications. 61 — © Capital One, 2016
  62. 62. THIS IS ACHIEVED VIA A READ OPERATION.62 — © Capital One, 2016
  63. 63. TYPICALLY COMES FROM THE KEYBOARD USED TO START63 — © Capital One, 2016
  64. 64. To listen in on data from stdin, use the data and end events: // stdin.js process.stdin.resume() process.stdin.setEncoding('utf8') process.stdin.on('data', function (chunk) { console.log('chunk: ', chunk) }) process.stdin.on('end', function () { console.log('--- END ---') }) 64 — © Capital One, 2016
  65. 65. DEMO $ node stdin.js 65 — © Capital One, 2016
  66. 66. NEW INTERFACE read() var readable = getReadableStreamSomehow() readable.on('readable', () => { var chunk while (null !== (chunk = readable.read())) { console.log('got %d bytes of data', chunk.length) } }) 66 — © Capital One, 2016
  67. 67. WRITABLE STREAM EXAMPLE process.stdout Standard output streams contain data going out of the applications. 67 — © Capital One, 2016
  68. 68. THIS IS DONE VIA A WRITE OPERATION.68 — © Capital One, 2016
  69. 69. DATA WRITTEN TO STANDARD OUTPUT IS VISIBLE ON THE69 — © Capital One, 2016
  70. 70. WRITABLE STREAM To write to stdout, use the write function: process.stdout.write('A simple messagen') 70 — © Capital One, 2016
  71. 71. WHAT ABOUT HTTP? 71 — © Capital One, 2016
  72. 72. const http = require('http') var server = http.createServer( (req, res) => { var body = '' req.setEncoding('utf8') req.on('data', (chunk) => { body += chunk }) req.on('end', () => { var data = JSON.parse(body) res.write(typeof data) res.end() }) }) server.listen(1337) 72 — © Capital One, 2016
  73. 73. PIPE var r = fs.createReadStream('file.txt') var z = zlib.createGzip() var w = fs.createWriteStream('file.txt.gz') r.pipe(z).pipe(w) 73 — © Capital One, 2016
  74. 74. WHAT DATA TYPE TO USE FOR BINARY DATA? 74 — © Capital One, 2016
  75. 75. BUFFERS Binary data type, to create: > new Buffer(size) > new Buffer(array) > new Buffer(buffer) > new Buffer(str[, encoding]) Docs: http://bit.ly/1IeAcZ175 — © Capital One, 2016
  76. 76. WORKING WITH BUFFER // buf.js var buf = new Buffer(26) for (var i = 0 ; i < 26 ; i++) { buf[i] = i + 97 // 97 is ASCII a } console.log(buf) // <Buffer 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a> console.log(buf.toString('utf8')) // abcdefghijklmnopqrstuvwxyz 76 — © Capital One, 2016
  77. 77. BUFFER CONVERTION buf.toString('ascii') // outputs: abcdefghijklmnopqrstuvwxyz buf.toString('ascii', 0, 5) // outputs: abcde buf.toString('utf8', 0, 5) // outputs: abcde buf.toString(undefined, 0, 5) // encoding defaults to 'utf8', outputs abcde 77 — © Capital One, 2016
  78. 78. REMEMBER FS? fs.readFile('/etc/passwd', function (err, data) { if (err) return console.error(err) console.log(data) }); data is buffer! 78 — © Capital One, 2016
  79. 79. DEMO $ node server-stream 79 — © Capital One, 2016
  80. 80. STREAMS AND BUFFER DEMO // server-stream.js app.get('/stream', function(req, res) { var stream = fs.createReadStream(largeImagePath) stream.pipe(res) }) $ node server-stream http://localhost:3000/stream http://localhost:3000/non-stream 80 — © Capital One, 2016
  81. 81. RESULTS IN DEVTOOLS /stream responds faster! X-Response-Time ~300ms vs. 3-5s 81 — © Capital One, 2016
  82. 82. STREAM RESOURCES https://github.com/substack/stream-adventure $ sudo npm install -g stream-adventure $ stream-adventure https://github.com/substack/stream-handbook 82 — © Capital One, 2016
  83. 83. HOW TO SCALE A SINGLE THREADED SYSTEM?83 — © Capital One, 2016
  84. 84. CLUSTER USAGE > Master: starts workers > Worker: do the job, e.g., HTTP server Number of processes = number of CPUs 84 — © Capital One, 2016
  85. 85. CLUSTERS var cluster = require('cluster') if (cluster.isMaster) { for (var i = 0; i < numCPUs; i++) { cluster.fork() } } else if (cluster.isWorker) { // your server code }) 85 — © Capital One, 2016
  86. 86. CLUSTER DEMO 1. Run code/cluster.js with node ($ node cluster.js). 2. Install loadtest with npm: $ npm install -g loadtest 3. Run load testing with: $ loadtest http:// localhost:3000 -t 20 —c 10 Press control+c on the server terminal86 — © Capital One, 2016
  87. 87. CLUSTER LIBRARIES > Core cluster: lean and mean > strong-cluster-control (https://github.com/ strongloop/strong-cluster-control), or `$ slc run`: good choice > pm2 (https://github.com/Unitech/pm2): good choice 87 — © Capital One, 2016
  88. 88. PM2 https://github.com/Unitech/pm2 http://pm2.keymetrics.io Advantages: > Load-balancer and other features > 0s reload down-time, i.e., forever alive 88 — © Capital One, 2016
  89. 89. PM2 DEMO: TYPICAL EXPRESS SERVER var express = require('express') var port = 3000 global.stats = {} console.log('worker (%s) is now listening to http://localhost:%s', process.pid, port) var app = express() app.get('*', function(req, res) { if (!global.stats[process.pid]) global.stats[process.pid] = 1 else global.stats[process.pid] += 1; var l ='cluser ' + process.pid + ' responded n'; console.log(l, global.stats) res.status(200).send(l) }) app.listen(port) 89 — © Capital One, 2016
  90. 90. PM2 DEMO Using server.js: $ pm2 start server.js -i 0 In a new window: $ loadtest http://localhost:3000 -t 20 -c 10 $ pm2 list 90 — © Capital One, 2016
  91. 91. SPAWN VS FORK VS EXEC > require('child_process').spawn() - large data, stream, no new V8 instance > require('child_process').fork() - new V8 instance, multiple workers > require('child_process').exec() - buffer, async, all the data at once 91 — © Capital One, 2016
  92. 92. SPAWN EXAMPLE fs = require('fs') process = require('child_process') var p = process.spawn('node', 'program.js') p.stdout.on('data', function(data)) { console.log('stdout: ' + data) }) 92 — © Capital One, 2016
  93. 93. FORK EXAMPLE fs = require('fs') process = require('child_process') var p = process.fork('program.js') p.stdout.on('data', function(data)) { console.log('stdout: ' + data) }) 93 — © Capital One, 2016
  94. 94. EXEC EXAMPLE fs = require('fs') process = require('child_process') var p = process.exec('node program.js', function (error, stdout, stderr) { if (error) console.log(error.code) }) 94 — © Capital One, 2016
  95. 95. HOW TO HANDLE ASYNC ERRORS? 95 — © Capital One, 2016
  96. 96. HANDLING ASYNC ERRORS Event Loop: Async errors are harder to handle/debug, because system loses context of the error. Then, application crashes. Try/catch is not good enough. 96 — © Capital One, 2016
  97. 97. SYNCHRONOUS ERROR IN NODE try { throw new Error('Fail!') } catch (e) { console.log('Custom Error: ' + e.message) } For sync errors try/catch works fine. 97 — © Capital One, 2016
  98. 98. ASYNC ERROR EXAMPLE try { setTimeout(function () { throw new Error('Fail!') }, Math.round(Math.random()*100)) } catch (e) { console.log('Custom Error: ' + e.message) } The app crashes! 98 — © Capital One, 2016
  99. 99. ME WHEN ASYNC ERROR'S THROWN 99 — © Capital One, 2016
  100. 100. ASYNC ERRORS How to deal with it? ! 100 — © Capital One, 2016
  101. 101. BEST PRACTICES FOR ASYNC ERRORS? > Listen to all “on error” events > Listen to uncaughtException > Use domain (soft deprecated) or AsyncWrap > Log, log, log & Trace > Notify (optional) > Exit & Restart the process 101 — © Capital One, 2016
  102. 102. ON('ERROR') Anything that inherits from or creates an instance of the above: Express, LoopBack, Sails, Hapi, etc. server.on('error', function (err) { console.error(err) }) 102 — © Capital One, 2016
  103. 103. ON('ERROR') CHAINED METHOD EXAMPLE var http = require(‘http’) var server = http.createServer(app) .on('error', function(e) { console.log(‘Failed to create server’) console.error(e) process.exit(1) }) 103 — © Capital One, 2016
  104. 104. ON(‘ERROR’) NAMED VARIABLE EXAMPLE var req = http.request(options, function(res) { // … processing the response }) req.on('error', function(e) { console.log('problem with request: ' + e.message) }) 104 — © Capital One, 2016
  105. 105. UNCAUGHTEXCEPTION uncaughtException is a very crude mechanism for exception handling. An unhandled exception means your application - and by extension Node.js itself - is in an undefined state. Blindly resuming means anything could happen. 105 — © Capital One, 2016
  106. 106. UNCAUGHTEXCEPTION Always listen to uncaughtException! process.on(‘uncaughtException’, handle) or process.addListener('uncaughtException', handle) 106 — © Capital One, 2016
  107. 107. UNCAUGHTEXCEPTION EXPANDED EXAMPLES process.on('uncaughtException', function (err) { console.error('uncaughtException: ', err.message) console.error(err.stack) process.exit(1) }) or process.addListener('uncaughtException', function (err) { console.error('uncaughtException: ', err.message) console.error(err.stack) process.exit(1) 107 — © Capital One, 2016
  108. 108. DOMAIN This module is softly deprecated in 4.0 (most likey will be separate from core module), but there's no alternatives in core as of now. 108 — © Capital One, 2016
  109. 109. DOMAIN EXAMPLE var domain = require('domain').create() domain.on('error', function(error){ console.log(error) }) domain.run(function(){ throw new Error('Failed!') }) 109 — © Capital One, 2016
  110. 110. DOMAIN WITH ASYNC ERROR DEMO domain-async.js: var d = require('domain').create() d.on('error', function(e) { console.log('Custom Error: ' + e) }) d.run(function() { setTimeout(function () { throw new Error('Failed!') }, Math.round(Math.random()*100)) }); 110 — © Capital One, 2016
  111. 111. C++ ADDONS 111 — © Capital One, 2016
  112. 112. HOW TO WRITE C/C++ BINDING FOR YOUR IOT, HARDWARE, DRONE, SMARTDEVICE, ETC.? 112 — © Capital One, 2016
  113. 113. NODE AND C++ Create the hello.cc file: #include <node.h> namespace demo { using v8::FunctionCallbackInfo; using v8::HandleScope; using v8::Isolate; using v8::Local; using v8::Object; using v8::String; using v8::Value; 113 — © Capital One, 2016
  114. 114. NODE AND C++ Create the hello.cc file: void Method(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); args.GetReturnValue().Set(String::NewFromUtf8(isolate, "capital one")); } void init(Local<Object> exports) { NODE_SET_METHOD(exports, "hello", Method); } NODE_MODULE(addon, init) } // namespace demo 114 — © Capital One, 2016
  115. 115. CREATING binding.gyp Create binding.gyp: { "targets": [ { "target_name": "addon", "sources": [ "hello.cc" ] } ] } 115 — © Capital One, 2016
  116. 116. NODE-GYP $ npm install -g node-gyp https://github.com/nodejs/node-gyp 116 — © Capital One, 2016
  117. 117. CONFIGURING AND BUILDING $ node-gyp configure $ node-gyp build Check for compiled .node files in build/Release/ 117 — © Capital One, 2016
  118. 118. C++ ADDONS EXAMPLES https://github.com/nodejs/node-addon-examples 118 — © Capital One, 2016
  119. 119. INCLUDING ADDON Create hello.js and include your C++ addon: var addon = require('./build/Release/addon') console.log(addon.hello()) // 'capital one' Run $ node hello.js 119 — © Capital One, 2016
  120. 120. CAPITAL ONE We use Node a lot! https://www.youtube.com/watch?v=BJPeLJhv1Ic 120 — © Capital One, 2016
  121. 121. 30-SECOND SUMMARY 1. Event Emitters 2. Streams 3. Buffers 4. Clusters 5. C++ Addons 6. Domain 121 — © Capital One, 2016
  122. 122. THE END 122 — © Capital One, 2016
  123. 123. SLIDES & CODE ! https://github.com/azat-co/you-dont-know-node or PDF: http://bit.ly/1VJWpQK 123 — © Capital One, 2016
  124. 124. Q&A ❓"➡$ Twitter: @azat_co Email: hi@azat.co 124 — © Capital One, 2016

×