SlideShare una empresa de Scribd logo
1 de 77
Descargar para leer sin conexión
Think Async
Asynchronous Patterns in NodeJS
- Adam L Barrett
Think Async
Asynchronous Patterns in NodeJS
- Adam L Barrett
JavaScript
Morning Exercise
What is Async?
A-synchronous?
Concurrency
Async vs Parallel
Async vs Parallel
JavaScript
Why care?
The Patterns…
The Patterns
• Callbacks

• Thunks

• Promises

• Tasks

• Observables

• Generators

• Async / Await

• Streams

• Async Iteration

• CSP
The Callback
The Callback
Continuation-Passing Style (CPS)

if you’re nasty 
fs.readFile('/foo.txt', (err, data) => {
// If an error occurred, handle it (throw, propagate, etc)
if(err) {
console.log('Unknown Error');
return;
}
// Otherwise, log the file contents
console.log(data);
});
• Can be called multiple times

• Controlled is given to the producer

• Is the basic JavaScript unit of work
Thunks
let foo = () => 1 + 2;
let foo = ( callback ) => callback(1 + 2);
// use it
foo(v => console.log(v));
const thunk = require('thunks')();
const fs = require('fs');
thunk( done => fs.stat('package.json', done) )(
(error, res) => console.log(error, res)
);
function makeASandwichWithSecretSauce(forPerson) {
return (dispatch) => {
return fetchSecretSauce().then(
sauce => dispatch( makeASandwich(forPerson) ),
error => dispatch( apologize(forPerson, error) )
);
};
}
• good for passing around work

• controlling the flow over time

• easy to understand
Promises
const verifyUser = function(username, password) {
database.verifyUser(username, password)
.then(userInfo => database.getRoles(userInfo))
.then(rolesInfo => database.logAccess(rolesInfo))
.then(finalResult => {
//do whatever the 'callback' would do
})
.catch(err => {
//do whatever the error handler needs
});
};
new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", '/api/ponies-of-equestria');
xhr.onload = () => resolve(xhr.responseText);
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
});
fetch(url)
.then(res => res.json())
.then(response => console.log('Success:', response))
.catch(error => console.error('Error:', error))
.finally(() => console.log('I will happen either way'));
• Eager, not lazy

• one value per promise

• immutable value once settled

• Can’t be cancelled (at this time)

• A crazy combination of map and
flatmap
Tasks
const task = new Task( (reject, resolve) => {
fs.readFile(path, (error, data) => {
if (error) reject(error)
else resolve(data)
})
})
task.fork(
error => { throw error },
data => { console.log(data) }
)
• Basically like promises without the
eager problem

• better for composition and such

• no crazy behaviour regarding
flatmapping
Observables
function listen(element, eventName) {
return new Observable( observer => {
// Create an event handler which sends data to the sink
let handler = event => observer.next(event);
// Attach the event handler
element.addEventListener(eventName, handler, true);
// Return a cleanup function which will cancel the stream
return () => {
// Detach the event handler from the element
element.removeEventListener(eventName, handler, true);
};
});
}
// Return an observable of special key down commands
function commandKeys(element) {
let keyCommands = { "38": "up", "40": "down" };
return listen(element, "keydown")
.filter(event => event.keyCode in keyCommands)
.map(event => keyCommands[event.keyCode])
}
let subscription = commandKeys(inputElement).subscribe({
next(val) { console.log("Received key command: " + val) },
error(err) { console.log("Received an error: " + err) },
complete() { console.log("Stream complete") },
});
Observable.from({
[Symbol.observable]() {
return new Observable(observer => {
setTimeout(() => {
observer.next("hello");
observer.next("world");
observer.complete();
}, 2000);
});
}
})
• Composable

• Lazy (don’t do anything until observer
subscribes)

• declarative

• multiple values over time
Generators
function* generator(i) {
yield i;
yield i + 10;
}
function* idMaker() {
var index = 0;
while (true) {
yield index++;
}
}
var gen = idMaker();
console.log( gen.next().value ); // 0
console.log( gen.next().value ); // 1
console.log( gen.next().value ); // 2
console.log( gen.next().value ); // 3
function* logGenerator() {
console.log( 0 );
console.log( 1, yield );
console.log( 2, yield );
console.log( 3, yield );
}
var gen = logGenerator();
gen.next(); // 0
gen.next( 'pretzel' ); // 1 pretzel
gen.next( 'california' ); // 2 california
gen.next( 'mayonnaise' ); // 3 mayonnaise
function* anotherGenerator( i ) {
yield i + 1;
yield i + 2;
}
function* generator( i ) {
yield i;
yield* anotherGenerator( i );
yield i + 10;
}
var gen = generator(10);
console.log( gen.next().value ); // 10
console.log( gen.next().value ); // 11
console.log( gen.next().value ); // 12
console.log( gen.next().value ); // 20
function* yieldAndReturn() {
yield "Y";
return "R";
yield "unreachable";
}
var gen = yieldAndReturn()
console.log(gen.next()); // { value: "Y", done: false }
console.log(gen.next()); // { value: "R", done: true }
console.log(gen.next()); // { value: undefined, done: true }
const myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...myIterable]; // [1, 2, 3]
co(function *(){
const userResult = yield fetch('/api/current-user');
const { id: user } = yield userResult.json();
const r = yield fetch('/api/books', qs.stringify({ user }));
const books = yield r.json();
return books;
})
.catch(onerror);
• Crazy powerful primitive for building on
top of

• makes creating iterables a snap

• very imperative

• led us to async / await
Async / Await
async function getCurrentUserBooks(){
const userResult = await fetch('/api/current-user');
const { id: user } = await userResult.json();
const r = await fetch('/api/books', qs.stringify({ user }));
return await r.json();
}
async function getAllTheThings(){
try {
await doSomethingAsync();
const results = await nowGetResults();
return await results.things.getAll();
} catch (err) {
handleErrorProperly(err)
}
}
const fs = require('fs');
const util = require('util');
// Convert fs.readFile into Promise version of same
const readFile = util.promisify(fs.readFile);
async function getStuff() {
return await readFile('test');
}
getStuff().then(data => {
console.log(data);
})
• Can clean up so much messy code

• highly composable

• limited in all the ways promises are

• no top level await (yet)
(async function(){
await initializeApp();
console.log('App Initialized');
}())
Streams
Streams
const fs = require('fs');
const server = require('http').createServer();
server.on('request', (req, res) => {
fs.readFile('./big.file', (err, data) => {
if (err) throw err;
res.end(data);
});
});
server.listen(8000);
const fs = require('fs');
const server = require('http').createServer();
server.on('request', (req, res) => {
const src = fs.createReadStream('./big.file');
src.pipe(res);
});
server.listen(8000);
const { Readable, Writable } = require('stream');
const { Transform, Duplex } = require('stream');
Readable - example fs.createReadStream()
Writable - example fs.createWriteStream()
Duplex - example net.Socket
Transform - example zlib.createDeflate()
readableSrcStream
.pipe(transformStream1)
.pipe(transformStream2)
.pipe(finalWrtitableDest)
const { Writable } = require('stream');
const outStream = new Writable({
write(chunk, encoding, callback) {
console.log(chunk.toString());
callback();
}
});
process.stdin.pipe(outStream);
const { Transform } = require('stream');
const commaSplitter = new Transform({
readableObjectMode: true,
transform(chunk, encoding, callback) {
this.push( chunk.toString().trim().split(',') );
callback();
}
});
• Should be your goto async abstraction
for nodejs

• somewhat declarative composition

• handles complex parts, like back
pressure for you

• Saves memory and resources
Async Iteration
async function asyncSum(asyncIterable) {
let result = 0;
const iterator = asyncIterable[Symbol.asyncIterator]();
while (true) {
const object = await iterator.next();
if (object.done)
break;
result += object.value;
}
return result;
}
// Signature: AsyncIterable ! AsyncIterable
async function* numberLines(lines) {
let n = 1;
for await (const line of lines) {
yield `${n} ${line}`;
n++;
}
}
async function* readLines(path) {
let file = await fileOpen(path);
try {
while (!file.EOF) {
yield await file.readLine();
}
} finally {
await file.close();
}
}
• Composable

• built in for-await-of

• still declarative

• multiple values over time
CSP
Think Async: Asynchronous Patterns in NodeJS
import Channel from 'async-csp';
let channel = new Channel();
async function puts(ch) {
await ch.put(1);
await ch.put(2);
await ch.put(3);
}
async function takes(ch) {
console.log(await ch.take()); // resolves to 1
console.log(await ch.take()); // resolves to 2
console.log(await ch.take()); // resolves to 3
}
puts(channel);
takes(channel);
// Channel × Channel ! void
async function numberLines(inputChannel, outputChannel) {
for (let n=1;; n++) {
const line = await inputChannel.take();
if (line === Channel.DONE) {
break;
}
outputChannel.put(`${n} ${line}`);
}
outputChannel.close();
}
import Channel from 'async-csp'
async function sleep(duration) {
return new Promise(resolve => setTimeout(resolve, duration))
}
async function player(name, table) {
while (true) {
let ball = await table.take();
if (ball === Channel.DONE) {
console.log('${name}: table is gone!');
break;
}
ball.hits++;
console.log('${name}! Hits: ${ball.hits}');
await sleep(100);
await table.put(ball);
}
}
async function pingPong() {
console.log('Opening ping-pong channel!');
let table = new Channel();
player('ping', table);
player('pong', table);
console.log('Serving ball...');
let ball = {hits: 0};
await table.put(ball);
await sleep(1000);
console.log('Closing ping-pong channel...');
table.close();
await table.done();
console.log('Channel is fully closed!');
console.log('Ball was hit ${ball.hits} times!');
}
pingPong()
import Channel from 'async-csp'
async function sleep(duration) {
return new Promise(resolve => setTimeout(resolve, duration))
}
async function player(name, table) {
while (true) {
let ball = await table.take();
if (ball === Channel.DONE) {
console.log('${name}: table is gone!');
break;
}
ball.hits++;
console.log('${name}! Hits: ${ball.hits}');
await sleep(100);
await table.put(ball);
}
}
async function sleep(duration) {
return new Promise(resolve => setTimeout(resolve, duration))
}
async function player(name, table) {
while (true) {
let ball = await table.take();
if (ball === Channel.DONE) {
console.log('${name}: table is gone!');
break;
}
ball.hits++;
console.log('${name}! Hits: ${ball.hits}');
await sleep(100);
await table.put(ball);
}
}
async function pingPong() {
console.log('Opening ping-pong channel!');
async function pingPong() {
console.log('Opening ping-pong channel!');
let table = new Channel();
player('ping', table);
player('pong', table);
console.log('Serving ball...');
let ball = {hits: 0};
await table.put(ball);
await sleep(1000);
console.log('Closing ping-pong channel...');
table.close();
await table.done();
console.log('Channel is fully closed!');
console.log('Ball was hit ${ball.hits} times!');
}
await table.put(ball);
await sleep(1000);
console.log('Closing ping-pong channel...');
table.close();
await table.done();
console.log('Channel is fully closed!');
console.log('Ball was hit ${ball.hits} times!');
}
pingPong()
Opening ping-pong channel!
Serving ball...
ping! Hits: 1
pong! Hits: 2
ping! Hits: 3
pong! Hits: 4
ping! Hits: 5
pong! Hits: 6
ping! Hits: 7
pong! Hits: 8
ping! Hits: 9
Closing ping-pong channel...
pong: table's gone!
Channel is fully closed!
Ball was hit 9 times!
ping: table's gone!
• Composable

• Great Separation of concerns

• error handling may be odd

• simple but powerful
The Patterns
• Callbacks

• Thunks

• Promises

• Tasks

• Observables

• Generators

• Async / Await

• Streams

• Async Iteration

• CSP
Think Async
Asynchronous Patterns in NodeJS
- Adam L Barrett
@adamlbarrett
BigAB

Más contenido relacionado

La actualidad más candente

rx.js make async programming simpler
rx.js make async programming simplerrx.js make async programming simpler
rx.js make async programming simplerAlexander Mostovenko
 
Callbacks and control flow in Node js
Callbacks and control flow in Node jsCallbacks and control flow in Node js
Callbacks and control flow in Node jsThomas Roch
 
Меняем javascript с помощью javascript
Меняем javascript с помощью javascriptМеняем javascript с помощью javascript
Меняем javascript с помощью javascriptPavel Volokitin
 
Using Reflections and Automatic Code Generation
Using Reflections and Automatic Code GenerationUsing Reflections and Automatic Code Generation
Using Reflections and Automatic Code GenerationIvan Dolgushin
 
Explaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to ComeExplaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to ComeCory Forsyth
 
ESCMAScript 6: Get Ready For The Future. Now
ESCMAScript 6: Get Ready For The Future. NowESCMAScript 6: Get Ready For The Future. Now
ESCMAScript 6: Get Ready For The Future. NowKrzysztof Szafranek
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptjnewmanux
 
Mastering Kotlin Standard Library
Mastering Kotlin Standard LibraryMastering Kotlin Standard Library
Mastering Kotlin Standard LibraryNelson Glauber Leal
 
The Promised Land (in Angular)
The Promised Land (in Angular)The Promised Land (in Angular)
The Promised Land (in Angular)Domenic Denicola
 
ES6 - Next Generation Javascript
ES6 - Next Generation JavascriptES6 - Next Generation Javascript
ES6 - Next Generation JavascriptRamesh Nair
 
Virtual machine and javascript engine
Virtual machine and javascript engineVirtual machine and javascript engine
Virtual machine and javascript engineDuoyi Wu
 
EcmaScript 6 - The future is here
EcmaScript 6 - The future is hereEcmaScript 6 - The future is here
EcmaScript 6 - The future is hereSebastiano Armeli
 
FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6Dmitry Soshnikov
 
Reactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwiftReactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwiftFlorent Pillet
 
Using Cerberus and PySpark to validate semi-structured datasets
Using Cerberus and PySpark to validate semi-structured datasetsUsing Cerberus and PySpark to validate semi-structured datasets
Using Cerberus and PySpark to validate semi-structured datasetsBartosz Konieczny
 

La actualidad más candente (20)

Map kit light
Map kit lightMap kit light
Map kit light
 
ES6 in Real Life
ES6 in Real LifeES6 in Real Life
ES6 in Real Life
 
rx.js make async programming simpler
rx.js make async programming simplerrx.js make async programming simpler
rx.js make async programming simpler
 
Rxjs ppt
Rxjs pptRxjs ppt
Rxjs ppt
 
Callbacks and control flow in Node js
Callbacks and control flow in Node jsCallbacks and control flow in Node js
Callbacks and control flow in Node js
 
Меняем javascript с помощью javascript
Меняем javascript с помощью javascriptМеняем javascript с помощью javascript
Меняем javascript с помощью javascript
 
Using Reflections and Automatic Code Generation
Using Reflections and Automatic Code GenerationUsing Reflections and Automatic Code Generation
Using Reflections and Automatic Code Generation
 
Explaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to ComeExplaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to Come
 
ESCMAScript 6: Get Ready For The Future. Now
ESCMAScript 6: Get Ready For The Future. NowESCMAScript 6: Get Ready For The Future. Now
ESCMAScript 6: Get Ready For The Future. Now
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScript
 
Mastering Kotlin Standard Library
Mastering Kotlin Standard LibraryMastering Kotlin Standard Library
Mastering Kotlin Standard Library
 
The Promised Land (in Angular)
The Promised Land (in Angular)The Promised Land (in Angular)
The Promised Land (in Angular)
 
ES6 - Next Generation Javascript
ES6 - Next Generation JavascriptES6 - Next Generation Javascript
ES6 - Next Generation Javascript
 
Virtual machine and javascript engine
Virtual machine and javascript engineVirtual machine and javascript engine
Virtual machine and javascript engine
 
EcmaScript 6 - The future is here
EcmaScript 6 - The future is hereEcmaScript 6 - The future is here
EcmaScript 6 - The future is here
 
Workshop 10: ECMAScript 6
Workshop 10: ECMAScript 6Workshop 10: ECMAScript 6
Workshop 10: ECMAScript 6
 
FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6
 
Reactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwiftReactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwift
 
Using Cerberus and PySpark to validate semi-structured datasets
Using Cerberus and PySpark to validate semi-structured datasetsUsing Cerberus and PySpark to validate semi-structured datasets
Using Cerberus and PySpark to validate semi-structured datasets
 
ES6 is Nigh
ES6 is NighES6 is Nigh
ES6 is Nigh
 

Similar a Think Async: Asynchronous Patterns in NodeJS

Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsPiotr Pelczar
 
Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jscacois
 
Job Queue in Golang
Job Queue in GolangJob Queue in Golang
Job Queue in GolangBo-Yi Wu
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Domenic Denicola
 
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015Michiel Borkent
 
Reactive programming on Android
Reactive programming on AndroidReactive programming on Android
Reactive programming on AndroidTomáš Kypta
 
Expert JavaScript tricks of the masters
Expert JavaScript  tricks of the mastersExpert JavaScript  tricks of the masters
Expert JavaScript tricks of the mastersAra Pehlivanian
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Ben Lesh
 
Concurrency on the JVM
Concurrency on the JVMConcurrency on the JVM
Concurrency on the JVMVaclav Pech
 
EcmaScript unchained
EcmaScript unchainedEcmaScript unchained
EcmaScript unchainedEduard Tomàs
 
Secrets of JavaScript Libraries
Secrets of JavaScript LibrariesSecrets of JavaScript Libraries
Secrets of JavaScript Librariesjeresig
 
Asynchronous programming with java script and node.js
Asynchronous programming with java script and node.jsAsynchronous programming with java script and node.js
Asynchronous programming with java script and node.jsTimur Shemsedinov
 

Similar a Think Async: Asynchronous Patterns in NodeJS (20)

Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
 
Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.js
 
ES6 Overview
ES6 OverviewES6 Overview
ES6 Overview
 
Job Queue in Golang
Job Queue in GolangJob Queue in Golang
Job Queue in Golang
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
 
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
 
Road to react hooks
Road to react hooksRoad to react hooks
Road to react hooks
 
Reactive programming on Android
Reactive programming on AndroidReactive programming on Android
Reactive programming on Android
 
Javascript
JavascriptJavascript
Javascript
 
Node js lecture
Node js lectureNode js lecture
Node js lecture
 
Expert JavaScript tricks of the masters
Expert JavaScript  tricks of the mastersExpert JavaScript  tricks of the masters
Expert JavaScript tricks of the masters
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016
 
Concurrency on the JVM
Concurrency on the JVMConcurrency on the JVM
Concurrency on the JVM
 
EcmaScript unchained
EcmaScript unchainedEcmaScript unchained
EcmaScript unchained
 
ES6: The Awesome Parts
ES6: The Awesome PartsES6: The Awesome Parts
ES6: The Awesome Parts
 
Secrets of JavaScript Libraries
Secrets of JavaScript LibrariesSecrets of JavaScript Libraries
Secrets of JavaScript Libraries
 
Day 1
Day 1Day 1
Day 1
 
Asynchronous programming with java script and node.js
Asynchronous programming with java script and node.jsAsynchronous programming with java script and node.js
Asynchronous programming with java script and node.js
 
Rxjs kyivjs 2015
Rxjs kyivjs 2015Rxjs kyivjs 2015
Rxjs kyivjs 2015
 
Node.js - Best practices
Node.js  - Best practicesNode.js  - Best practices
Node.js - Best practices
 

Último

NIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopNIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopBachir Benyammi
 
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdfUiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdfDianaGray10
 
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve DecarbonizationUsing IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve DecarbonizationIES VE
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintMahmoud Rabie
 
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UbiTrack UK
 
Digital magic. A small project for controlling smart light bulbs.
Digital magic. A small project for controlling smart light bulbs.Digital magic. A small project for controlling smart light bulbs.
Digital magic. A small project for controlling smart light bulbs.francesco barbera
 
Linked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesLinked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesDavid Newbury
 
Introduction to Quantum Computing
Introduction to Quantum ComputingIntroduction to Quantum Computing
Introduction to Quantum ComputingGDSC PJATK
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6DianaGray10
 
Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1DianaGray10
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding TeamAdam Moalla
 
Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™Adtran
 
Cloud Revolution: Exploring the New Wave of Serverless Spatial Data
Cloud Revolution: Exploring the New Wave of Serverless Spatial DataCloud Revolution: Exploring the New Wave of Serverless Spatial Data
Cloud Revolution: Exploring the New Wave of Serverless Spatial DataSafe Software
 
Videogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfVideogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfinfogdgmi
 
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfIaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfDaniel Santiago Silva Capera
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8DianaGray10
 
Spring24-Release Overview - Wellingtion User Group-1.pdf
Spring24-Release Overview - Wellingtion User Group-1.pdfSpring24-Release Overview - Wellingtion User Group-1.pdf
Spring24-Release Overview - Wellingtion User Group-1.pdfAnna Loughnan Colquhoun
 
PicPay - GenAI Finance Assistant - ChatGPT for Customer Service
PicPay - GenAI Finance Assistant - ChatGPT for Customer ServicePicPay - GenAI Finance Assistant - ChatGPT for Customer Service
PicPay - GenAI Finance Assistant - ChatGPT for Customer ServiceRenan Moreira de Oliveira
 
Designing A Time bound resource download URL
Designing A Time bound resource download URLDesigning A Time bound resource download URL
Designing A Time bound resource download URLRuncy Oommen
 

Último (20)

NIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopNIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 Workshop
 
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdfUiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
 
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve DecarbonizationUsing IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership Blueprint
 
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
 
Digital magic. A small project for controlling smart light bulbs.
Digital magic. A small project for controlling smart light bulbs.Digital magic. A small project for controlling smart light bulbs.
Digital magic. A small project for controlling smart light bulbs.
 
Linked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesLinked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond Ontologies
 
Introduction to Quantum Computing
Introduction to Quantum ComputingIntroduction to Quantum Computing
Introduction to Quantum Computing
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6
 
Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team
 
Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™
 
Cloud Revolution: Exploring the New Wave of Serverless Spatial Data
Cloud Revolution: Exploring the New Wave of Serverless Spatial DataCloud Revolution: Exploring the New Wave of Serverless Spatial Data
Cloud Revolution: Exploring the New Wave of Serverless Spatial Data
 
Videogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfVideogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdf
 
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfIaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8
 
Spring24-Release Overview - Wellingtion User Group-1.pdf
Spring24-Release Overview - Wellingtion User Group-1.pdfSpring24-Release Overview - Wellingtion User Group-1.pdf
Spring24-Release Overview - Wellingtion User Group-1.pdf
 
PicPay - GenAI Finance Assistant - ChatGPT for Customer Service
PicPay - GenAI Finance Assistant - ChatGPT for Customer ServicePicPay - GenAI Finance Assistant - ChatGPT for Customer Service
PicPay - GenAI Finance Assistant - ChatGPT for Customer Service
 
Designing A Time bound resource download URL
Designing A Time bound resource download URLDesigning A Time bound resource download URL
Designing A Time bound resource download URL
 

Think Async: Asynchronous Patterns in NodeJS

  • 1. Think Async Asynchronous Patterns in NodeJS - Adam L Barrett
  • 2. Think Async Asynchronous Patterns in NodeJS - Adam L Barrett JavaScript
  • 11. The Patterns • Callbacks • Thunks • Promises • Tasks • Observables • Generators • Async / Await • Streams • Async Iteration • CSP
  • 13. The Callback Continuation-Passing Style (CPS)
 if you’re nasty 
  • 14. fs.readFile('/foo.txt', (err, data) => { // If an error occurred, handle it (throw, propagate, etc) if(err) { console.log('Unknown Error'); return; } // Otherwise, log the file contents console.log(data); });
  • 15. • Can be called multiple times • Controlled is given to the producer • Is the basic JavaScript unit of work
  • 17. let foo = () => 1 + 2;
  • 18. let foo = ( callback ) => callback(1 + 2); // use it foo(v => console.log(v));
  • 19. const thunk = require('thunks')(); const fs = require('fs'); thunk( done => fs.stat('package.json', done) )( (error, res) => console.log(error, res) );
  • 20. function makeASandwichWithSecretSauce(forPerson) { return (dispatch) => { return fetchSecretSauce().then( sauce => dispatch( makeASandwich(forPerson) ), error => dispatch( apologize(forPerson, error) ) ); }; }
  • 21. • good for passing around work • controlling the flow over time • easy to understand
  • 23. const verifyUser = function(username, password) { database.verifyUser(username, password) .then(userInfo => database.getRoles(userInfo)) .then(rolesInfo => database.logAccess(rolesInfo)) .then(finalResult => { //do whatever the 'callback' would do }) .catch(err => { //do whatever the error handler needs }); };
  • 24. new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", '/api/ponies-of-equestria'); xhr.onload = () => resolve(xhr.responseText); xhr.onerror = () => reject(xhr.statusText); xhr.send(); });
  • 25. fetch(url) .then(res => res.json()) .then(response => console.log('Success:', response)) .catch(error => console.error('Error:', error)) .finally(() => console.log('I will happen either way'));
  • 26. • Eager, not lazy • one value per promise • immutable value once settled • Can’t be cancelled (at this time) • A crazy combination of map and flatmap
  • 27. Tasks
  • 28. const task = new Task( (reject, resolve) => { fs.readFile(path, (error, data) => { if (error) reject(error) else resolve(data) }) }) task.fork( error => { throw error }, data => { console.log(data) } )
  • 29. • Basically like promises without the eager problem • better for composition and such • no crazy behaviour regarding flatmapping
  • 31. function listen(element, eventName) { return new Observable( observer => { // Create an event handler which sends data to the sink let handler = event => observer.next(event); // Attach the event handler element.addEventListener(eventName, handler, true); // Return a cleanup function which will cancel the stream return () => { // Detach the event handler from the element element.removeEventListener(eventName, handler, true); }; }); }
  • 32. // Return an observable of special key down commands function commandKeys(element) { let keyCommands = { "38": "up", "40": "down" }; return listen(element, "keydown") .filter(event => event.keyCode in keyCommands) .map(event => keyCommands[event.keyCode]) }
  • 33. let subscription = commandKeys(inputElement).subscribe({ next(val) { console.log("Received key command: " + val) }, error(err) { console.log("Received an error: " + err) }, complete() { console.log("Stream complete") }, });
  • 34. Observable.from({ [Symbol.observable]() { return new Observable(observer => { setTimeout(() => { observer.next("hello"); observer.next("world"); observer.complete(); }, 2000); }); } })
  • 35. • Composable • Lazy (don’t do anything until observer subscribes) • declarative • multiple values over time
  • 37. function* generator(i) { yield i; yield i + 10; }
  • 38. function* idMaker() { var index = 0; while (true) { yield index++; } } var gen = idMaker(); console.log( gen.next().value ); // 0 console.log( gen.next().value ); // 1 console.log( gen.next().value ); // 2 console.log( gen.next().value ); // 3
  • 39. function* logGenerator() { console.log( 0 ); console.log( 1, yield ); console.log( 2, yield ); console.log( 3, yield ); } var gen = logGenerator(); gen.next(); // 0 gen.next( 'pretzel' ); // 1 pretzel gen.next( 'california' ); // 2 california gen.next( 'mayonnaise' ); // 3 mayonnaise
  • 40. function* anotherGenerator( i ) { yield i + 1; yield i + 2; } function* generator( i ) { yield i; yield* anotherGenerator( i ); yield i + 10; } var gen = generator(10); console.log( gen.next().value ); // 10 console.log( gen.next().value ); // 11 console.log( gen.next().value ); // 12 console.log( gen.next().value ); // 20
  • 41. function* yieldAndReturn() { yield "Y"; return "R"; yield "unreachable"; } var gen = yieldAndReturn() console.log(gen.next()); // { value: "Y", done: false } console.log(gen.next()); // { value: "R", done: true } console.log(gen.next()); // { value: undefined, done: true }
  • 42. const myIterable = {}; myIterable[Symbol.iterator] = function* () { yield 1; yield 2; yield 3; }; [...myIterable]; // [1, 2, 3]
  • 43. co(function *(){ const userResult = yield fetch('/api/current-user'); const { id: user } = yield userResult.json(); const r = yield fetch('/api/books', qs.stringify({ user })); const books = yield r.json(); return books; }) .catch(onerror);
  • 44. • Crazy powerful primitive for building on top of • makes creating iterables a snap • very imperative • led us to async / await
  • 46. async function getCurrentUserBooks(){ const userResult = await fetch('/api/current-user'); const { id: user } = await userResult.json(); const r = await fetch('/api/books', qs.stringify({ user })); return await r.json(); }
  • 47. async function getAllTheThings(){ try { await doSomethingAsync(); const results = await nowGetResults(); return await results.things.getAll(); } catch (err) { handleErrorProperly(err) } }
  • 48. const fs = require('fs'); const util = require('util'); // Convert fs.readFile into Promise version of same const readFile = util.promisify(fs.readFile); async function getStuff() { return await readFile('test'); } getStuff().then(data => { console.log(data); })
  • 49. • Can clean up so much messy code • highly composable • limited in all the ways promises are • no top level await (yet)
  • 53. const fs = require('fs'); const server = require('http').createServer(); server.on('request', (req, res) => { fs.readFile('./big.file', (err, data) => { if (err) throw err; res.end(data); }); }); server.listen(8000);
  • 54. const fs = require('fs'); const server = require('http').createServer(); server.on('request', (req, res) => { const src = fs.createReadStream('./big.file'); src.pipe(res); }); server.listen(8000);
  • 55. const { Readable, Writable } = require('stream'); const { Transform, Duplex } = require('stream'); Readable - example fs.createReadStream() Writable - example fs.createWriteStream() Duplex - example net.Socket Transform - example zlib.createDeflate()
  • 57. const { Writable } = require('stream'); const outStream = new Writable({ write(chunk, encoding, callback) { console.log(chunk.toString()); callback(); } }); process.stdin.pipe(outStream);
  • 58. const { Transform } = require('stream'); const commaSplitter = new Transform({ readableObjectMode: true, transform(chunk, encoding, callback) { this.push( chunk.toString().trim().split(',') ); callback(); } });
  • 59. • Should be your goto async abstraction for nodejs • somewhat declarative composition • handles complex parts, like back pressure for you • Saves memory and resources
  • 61. async function asyncSum(asyncIterable) { let result = 0; const iterator = asyncIterable[Symbol.asyncIterator](); while (true) { const object = await iterator.next(); if (object.done) break; result += object.value; } return result; }
  • 62. // Signature: AsyncIterable ! AsyncIterable async function* numberLines(lines) { let n = 1; for await (const line of lines) { yield `${n} ${line}`; n++; } }
  • 63. async function* readLines(path) { let file = await fileOpen(path); try { while (!file.EOF) { yield await file.readLine(); } } finally { await file.close(); } }
  • 64. • Composable • built in for-await-of • still declarative • multiple values over time
  • 65. CSP
  • 67. import Channel from 'async-csp'; let channel = new Channel(); async function puts(ch) { await ch.put(1); await ch.put(2); await ch.put(3); } async function takes(ch) { console.log(await ch.take()); // resolves to 1 console.log(await ch.take()); // resolves to 2 console.log(await ch.take()); // resolves to 3 } puts(channel); takes(channel);
  • 68. // Channel × Channel ! void async function numberLines(inputChannel, outputChannel) { for (let n=1;; n++) { const line = await inputChannel.take(); if (line === Channel.DONE) { break; } outputChannel.put(`${n} ${line}`); } outputChannel.close(); }
  • 69. import Channel from 'async-csp' async function sleep(duration) { return new Promise(resolve => setTimeout(resolve, duration)) } async function player(name, table) { while (true) { let ball = await table.take(); if (ball === Channel.DONE) { console.log('${name}: table is gone!'); break; } ball.hits++; console.log('${name}! Hits: ${ball.hits}'); await sleep(100); await table.put(ball); } } async function pingPong() { console.log('Opening ping-pong channel!'); let table = new Channel(); player('ping', table); player('pong', table); console.log('Serving ball...'); let ball = {hits: 0}; await table.put(ball); await sleep(1000); console.log('Closing ping-pong channel...'); table.close(); await table.done(); console.log('Channel is fully closed!'); console.log('Ball was hit ${ball.hits} times!'); } pingPong()
  • 70. import Channel from 'async-csp' async function sleep(duration) { return new Promise(resolve => setTimeout(resolve, duration)) } async function player(name, table) { while (true) { let ball = await table.take(); if (ball === Channel.DONE) { console.log('${name}: table is gone!'); break; } ball.hits++; console.log('${name}! Hits: ${ball.hits}'); await sleep(100); await table.put(ball); } }
  • 71. async function sleep(duration) { return new Promise(resolve => setTimeout(resolve, duration)) } async function player(name, table) { while (true) { let ball = await table.take(); if (ball === Channel.DONE) { console.log('${name}: table is gone!'); break; } ball.hits++; console.log('${name}! Hits: ${ball.hits}'); await sleep(100); await table.put(ball); } } async function pingPong() { console.log('Opening ping-pong channel!');
  • 72. async function pingPong() { console.log('Opening ping-pong channel!'); let table = new Channel(); player('ping', table); player('pong', table); console.log('Serving ball...'); let ball = {hits: 0}; await table.put(ball); await sleep(1000); console.log('Closing ping-pong channel...'); table.close(); await table.done(); console.log('Channel is fully closed!'); console.log('Ball was hit ${ball.hits} times!'); }
  • 73. await table.put(ball); await sleep(1000); console.log('Closing ping-pong channel...'); table.close(); await table.done(); console.log('Channel is fully closed!'); console.log('Ball was hit ${ball.hits} times!'); } pingPong()
  • 74. Opening ping-pong channel! Serving ball... ping! Hits: 1 pong! Hits: 2 ping! Hits: 3 pong! Hits: 4 ping! Hits: 5 pong! Hits: 6 ping! Hits: 7 pong! Hits: 8 ping! Hits: 9 Closing ping-pong channel... pong: table's gone! Channel is fully closed! Ball was hit 9 times! ping: table's gone!
  • 75. • Composable • Great Separation of concerns • error handling may be odd • simple but powerful
  • 76. The Patterns • Callbacks • Thunks • Promises • Tasks • Observables • Generators • Async / Await • Streams • Async Iteration • CSP
  • 77. Think Async Asynchronous Patterns in NodeJS - Adam L Barrett @adamlbarrett BigAB