SlideShare ist ein Scribd-Unternehmen logo
1 von 36
Downloaden Sie, um offline zu lesen
From Node.js to Design Patterns
Luciano Mammino
@loige
👋 Hello, I am Luciano
Cloud & Full stack software engineer
nodejsdesignpatterns.com
Let’s connect:
🌎 loige.co
🐦 @loige
🧳 lucianomammino
👇 Get the slides (and click around…)
loige.link/devcast
@loige
What is Node.js
Node.js is an open-source, cross-platform,
JavaScript runtime environment that executes
JavaScript code outside a web browser.
@loige
Node.js + JavaScript: when?
● Building for the web
○ Websites, APIs, Servers, Single Page Applications, Bots, etc…
● Command-line applications and tools
● Mobile applications (React Native, Ionic, NativeScript, etc.)
● Desktop apps (Electron)
● Embedded & IoT (Espruino, Johnny-Five)
@loige
Async I/O
In JavaScript and in Node.js, input/output operations (e.g. making an HTTP
request) are non-blocking.
@loige
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://google.com")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
System.out.println("Request completed");
A blocking HTTP request (Java)
Output
blocking...
blocking...
<google home page HTML code>
Request completed
Code executed
“In order”
@loige
Is blocking I/O bad?
It depends…
If your application is I/O heavy, then you might have a problem...
@loige
Let’s make 3 requests...
Req 1
Req 2
Req 3
time
@loige
You can always use threads...
Req 1
Req 2
Req 3
time
But threads are…
Complicated
Expensive
A lot of idle time per thread!
wait...
wait...
wait...
@loige
client.get('https://google.com',
(err, resp) => {
console.log(resp.body)
}
)
console.log('Request completed (?)')
👍
With Node.js async I/O
Output
Request “in the
background”
Request completed (?)
<google home page HTML code>
⚠ Code executed
“OUT of order”
Not really completed!
Non-blocking:
execution continues
Callback function
1
2
3
@loige
Mental model
You “just” schedule async I/O and you will get notified when the
operation is completed!
● Async I/O happens in the background asynchronously
● You don’t have to manage threads to get concurrency!
@loige
Let’s do 3 requests with Async I/O
“User” thread
Event loop
(libuv)
time
idle... idle... idle...
Simpler code for the user
Idle time only in one thread
Sched. req1
Sched. req2
Sched. req3 req1 result req3 result req2 result
@loige
I am oversimplifying a bit… 😛
Watch loige.link/event-loop-what-the-heck
if you want to go more in depth!
@loige
Many ways to handle
async flows
@loige
Delete last reservation if confirmed
● Get a guest object from a guest id (async)
● Get the last reservation from the guest object
● Get the details of that reservation (async)
● Delete that reservation if “confirmed” (async)
@loige
Callbacks
function deleteLastReservationIfConfirmed (client, guestId, cb) {
client.getGuest(guestId, (err, guest) => {
if (err) { return cb(err) }
const lastReservation = guest.reservations.pop()
if (typeof lastReservation === 'undefined') {
return cb(null, false)
}
client.getReservation(lastReservation, (err, reservation) => {
if (err) { return cb(err) }
if (reservation.status === 'confirmed') {
client.deleteReservation(reservation.id, (err) => {
if (err) { return cb(err) }
return cb(null, true)
})
}
})
})
}
@loige
Promises
function deleteLastReservationIfConfirmed (client, guestId) {
return client.getGuest(guestId)
.then((guest) => {
const lastReservation = guest.reservations.pop()
if (typeof lastReservation !== 'undefined') {
return client.getReservation(lastReservation)
}
})
.then((reservation) => {
if (!reservation || reservation.status !== 'confirmed') {
return false
}
return client.deleteReservation(reservation.id)
})
}
@loige
Async/Await
async function deleteLastReservationIfConfirmed (client, guestId) {
const guest = await client.getGuest(guestId)
const lastReservation = guest.reservations.pop()
if (typeof lastReservation === 'undefined') {
return false
}
const reservation = await client.getReservation(lastReservation)
if (!reservation || reservation.status !== 'confirmed') {
return false
}
return client.deleteReservation(reservation.id)
}
@loige
Advantages of Async/Await
● Easier to read and reason about (“sequential flow”)
● Easier to deal with conditional async operations
● Unified error handling
(you can catch both synchronous and asynchronous errors)
⚠ To fully understand async/await, you still need to understand callbacks and
promises, don’t ignore them!
@loige
Other ways to handle async
● Events
● Streams
● Async iterators/generators
@loige
Some interesting
async patterns
@loige
const guestIds = ['Peach', 'Toad', 'Mario', 'Luigi']
for (const guestId of guestIds) {
await deleteLastReservationIfConfirmed(client, guestId)
}
Sequential execution
@loige
const guestIds = ['Peach', 'Toad', 'Mario', 'Luigi']
guestIds.forEach(async (guestId) => {
await deleteLastReservationIfConfirmed(client, guestId)
})
Sequential execution ⚠ Common pitfall
Don’t use Array.map or Array.forEach!
forEach will run all the functions without awaiting them, so all the delete
invocations will happen concurrently!
@loige
const guestIds = ['Peach', 'Toad', 'Mario', 'Luigi']
await Promise.all(
guestIds.map(
guestId => deleteLastReservationIfConfirmed(client, guestId)
)
)
Concurrent execution
⚠ Promise.all rejects as soon as one promise rejects. A failure will result in the failure of the entire operation.
@loige
const guestIds = ['Peach', 'Toad', 'Mario', 'Luigi']
const results = await Promise.allSettled(
guestIds.map(
guestId => deleteLastReservationIfConfirmed(client, guestId)
)
)
Concurrent execution - Alternative
[
{ status: 'fulfilled', value: true },
{ status: 'fulfilled', value: true },
{ status: 'rejected', reason: Error },
{ status: 'fulfilled', value: true }
]
@loige
const mapLimit = require('async/mapLimit')
const guestIds = ['Peach', 'Toad', 'Mario', 'Luigi', '...']
const results = await mapLimit(
guestIds,
2, // max concurrency
async (guestId) => deleteLastReservationIfConfirmed(client, guestId)
)
Concurrent execution - limited
When you have a lot of tasks to run and what to keep limited concurrency
Uses the third-party async module (npm.im/async)
@loige
Request batching
Classic flow - one user
HTTP
Server DB
/availability/v1/units
@loige
Request batching
Classic flow - multiple users (no batching)
HTTP
Server DB
/availability/v1/units
/availability/v1/units
/availability/v1/units
@loige
Request batching
Classic flow - multiple users (with batching!)
HTTP
Server DB
/availability/v1/units
/availability/v1/units
/availability/v1/units
📘 Requests in-flight
pending
fulfilled
⏱ /availability/v1/units
⏱
@loige
const { createServer } = require('http')
const server = createServer(async (req, res) => {
const url = new URL(req.url, 'http://localhost')
if (url.pathname !== '/availability/v1/units') {
res.writeHead(404, 'Not found')
return res.end()
}
const units = await getAvailableUnitsFromDb()
res.writeHead(200)
res.end(JSON.stringify(units))
})
server.listen(8000)
The web server
@loige
let pendingRequest = null
async function getAvailableUnitsFromDb () {
if (pendingRequest) {
console.log('batching')
return pendingRequest
}
console.log('Getting data from db')
pendingRequest = db.query('SELECT * FROM units WHERE "availability" > 0')
pendingRequest.finally(() => {
pendingRequest = null
})
return pendingRequest
}
Get units from DB
@loige
Performance comparison
Without batching With batching
+15%
throughput
@loige
In conclusion
● Node.js is a great runtime for I/O bound applications
● It’s also great for full stack web development
● The async model allows you to express concurrent computation effectively
● You still need to master callbacks, promises and async / await!
● There are many patterns that can help you out to keep your code organised
and more performant.
@loige
Want to learn more?
● nodejsdesignpatterns.com - possibly a great book :)
● loige.link/javascript-mdn - mozilla guides
● eloquentjavascript.net - free e-book
● freecodecamp.org - interactive code training
● nodejs.org/api - Node.js official docs
@loige
Thank you!
loige.link/devcast
@loige

Weitere ähnliche Inhalte

Was ist angesagt?

Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010
Ismael Celis
 

Was ist angesagt? (20)

Workshop 12: AngularJS Parte I
Workshop 12: AngularJS Parte IWorkshop 12: AngularJS Parte I
Workshop 12: AngularJS Parte I
 
JavaScript and the AST
JavaScript and the ASTJavaScript and the AST
JavaScript and the AST
 
ES2015 workflows
ES2015 workflowsES2015 workflows
ES2015 workflows
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
 
Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010
 
Callbacks, promises, generators - asynchronous javascript
Callbacks, promises, generators - asynchronous javascriptCallbacks, promises, generators - asynchronous javascript
Callbacks, promises, generators - asynchronous javascript
 
dSS API by example
dSS API by exampledSS API by example
dSS API by example
 
Optimizing a large angular application (ng conf)
Optimizing a large angular application (ng conf)Optimizing a large angular application (ng conf)
Optimizing a large angular application (ng conf)
 
_Function Builders in Swift #love_swift
_Function Builders in Swift #love_swift_Function Builders in Swift #love_swift
_Function Builders in Swift #love_swift
 
Async js - Nemetschek Presentaion @ HackBulgaria
Async js - Nemetschek Presentaion @ HackBulgariaAsync js - Nemetschek Presentaion @ HackBulgaria
Async js - Nemetschek Presentaion @ HackBulgaria
 
Node.js for PHP developers
Node.js for PHP developersNode.js for PHP developers
Node.js for PHP developers
 
The evolution of java script asynchronous calls
The evolution of java script asynchronous callsThe evolution of java script asynchronous calls
The evolution of java script asynchronous calls
 
Blockchain Coding Dojo - BlockchainHub Graz
Blockchain Coding Dojo - BlockchainHub GrazBlockchain Coding Dojo - BlockchainHub Graz
Blockchain Coding Dojo - BlockchainHub Graz
 
PyconIE 2016 - Kajiki, the fast and validated template engine your were looki...
PyconIE 2016 - Kajiki, the fast and validated template engine your were looki...PyconIE 2016 - Kajiki, the fast and validated template engine your were looki...
PyconIE 2016 - Kajiki, the fast and validated template engine your were looki...
 
Javascript
JavascriptJavascript
Javascript
 
Correcting Common .NET Async/Await Mistakes
Correcting Common .NET Async/Await MistakesCorrecting Common .NET Async/Await Mistakes
Correcting Common .NET Async/Await Mistakes
 
ng-conf 2017: Angular Mischief Maker Slides
ng-conf 2017: Angular Mischief Maker Slidesng-conf 2017: Angular Mischief Maker Slides
ng-conf 2017: Angular Mischief Maker Slides
 
Correcting Common Async/Await Mistakes in .NET
Correcting Common Async/Await Mistakes in .NETCorrecting Common Async/Await Mistakes in .NET
Correcting Common Async/Await Mistakes in .NET
 
Java with a Clojure mindset
Java with a Clojure mindsetJava with a Clojure mindset
Java with a Clojure mindset
 
Introducing perf budgets on CI with puppeteer - perf.now()
Introducing perf budgets on CI with puppeteer - perf.now()Introducing perf budgets on CI with puppeteer - perf.now()
Introducing perf budgets on CI with puppeteer - perf.now()
 

Ähnlich wie From Node.js to Design Patterns

Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 
CompletableFuture
CompletableFutureCompletableFuture
CompletableFuture
koji lin
 
Psgi Plack Sfpm
Psgi Plack SfpmPsgi Plack Sfpm
Psgi Plack Sfpm
som_nangia
 
Psgi Plack Sfpm
Psgi Plack SfpmPsgi Plack Sfpm
Psgi Plack Sfpm
wilburlo
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
Yekmer Simsek
 

Ähnlich wie From Node.js to Design Patterns (20)

An opinionated intro to Node.js - devrupt hospitality hackathon
An opinionated intro to Node.js - devrupt hospitality hackathonAn opinionated intro to Node.js - devrupt hospitality hackathon
An opinionated intro to Node.js - devrupt hospitality hackathon
 
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
 
From Node.js to Design Patterns - BuildPiper
From Node.js to Design Patterns - BuildPiperFrom Node.js to Design Patterns - BuildPiper
From Node.js to Design Patterns - BuildPiper
 
JavaScript Promises
JavaScript PromisesJavaScript Promises
JavaScript Promises
 
Por que Criamos uma Ferramenta de Load Testing utilizando Playwright e AWS Ba...
Por que Criamos uma Ferramenta de Load Testing utilizando Playwright e AWS Ba...Por que Criamos uma Ferramenta de Load Testing utilizando Playwright e AWS Ba...
Por que Criamos uma Ferramenta de Load Testing utilizando Playwright e AWS Ba...
 
Playing With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.jsPlaying With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.js
 
Javascript: repetita iuvant
Javascript: repetita iuvantJavascript: repetita iuvant
Javascript: repetita iuvant
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Writing JavaScript for C# Blazor.pptx
Writing JavaScript for C# Blazor.pptxWriting JavaScript for C# Blazor.pptx
Writing JavaScript for C# Blazor.pptx
 
Side effects-con-redux
Side effects-con-reduxSide effects-con-redux
Side effects-con-redux
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.js
 
Intro to Asynchronous Javascript
Intro to Asynchronous JavascriptIntro to Asynchronous Javascript
Intro to Asynchronous Javascript
 
CompletableFuture
CompletableFutureCompletableFuture
CompletableFuture
 
Avoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promisesAvoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promises
 
The State of JavaScript (2015)
The State of JavaScript (2015)The State of JavaScript (2015)
The State of JavaScript (2015)
 
Psgi Plack Sfpm
Psgi Plack SfpmPsgi Plack Sfpm
Psgi Plack Sfpm
 
Psgi Plack Sfpm
Psgi Plack SfpmPsgi Plack Sfpm
Psgi Plack Sfpm
 
Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
 
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
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 

Mehr von Luciano Mammino

Mehr von Luciano Mammino (20)

Did you know JavaScript has iterators? DublinJS
Did you know JavaScript has iterators? DublinJSDid you know JavaScript has iterators? DublinJS
Did you know JavaScript has iterators? DublinJS
 
What I learned by solving 50 Advent of Code challenges in Rust - RustNation U...
What I learned by solving 50 Advent of Code challenges in Rust - RustNation U...What I learned by solving 50 Advent of Code challenges in Rust - RustNation U...
What I learned by solving 50 Advent of Code challenges in Rust - RustNation U...
 
Building an invite-only microsite with Next.js & Airtable - ReactJS Milano
Building an invite-only microsite with Next.js & Airtable - ReactJS MilanoBuilding an invite-only microsite with Next.js & Airtable - ReactJS Milano
Building an invite-only microsite with Next.js & Airtable - ReactJS Milano
 
Let's build a 0-cost invite-only website with Next.js and Airtable!
Let's build a 0-cost invite-only website with Next.js and Airtable!Let's build a 0-cost invite-only website with Next.js and Airtable!
Let's build a 0-cost invite-only website with Next.js and Airtable!
 
Everything I know about S3 pre-signed URLs
Everything I know about S3 pre-signed URLsEverything I know about S3 pre-signed URLs
Everything I know about S3 pre-signed URLs
 
Serverless for High Performance Computing
Serverless for High Performance ComputingServerless for High Performance Computing
Serverless for High Performance Computing
 
Serverless for High Performance Computing
Serverless for High Performance ComputingServerless for High Performance Computing
Serverless for High Performance Computing
 
JavaScript Iteration Protocols - Workshop NodeConf EU 2022
JavaScript Iteration Protocols - Workshop NodeConf EU 2022JavaScript Iteration Protocols - Workshop NodeConf EU 2022
JavaScript Iteration Protocols - Workshop NodeConf EU 2022
 
Building an invite-only microsite with Next.js & Airtable
Building an invite-only microsite with Next.js & AirtableBuilding an invite-only microsite with Next.js & Airtable
Building an invite-only microsite with Next.js & Airtable
 
Let's take the monolith to the cloud 🚀
Let's take the monolith to the cloud 🚀Let's take the monolith to the cloud 🚀
Let's take the monolith to the cloud 🚀
 
A look inside the European Covid Green Certificate - Rust Dublin
A look inside the European Covid Green Certificate - Rust DublinA look inside the European Covid Green Certificate - Rust Dublin
A look inside the European Covid Green Certificate - Rust Dublin
 
Monoliths to the cloud!
Monoliths to the cloud!Monoliths to the cloud!
Monoliths to the cloud!
 
The senior dev
The senior devThe senior dev
The senior dev
 
Node.js: scalability tips - Azure Dev Community Vijayawada
Node.js: scalability tips - Azure Dev Community VijayawadaNode.js: scalability tips - Azure Dev Community Vijayawada
Node.js: scalability tips - Azure Dev Community Vijayawada
 
A look inside the European Covid Green Certificate (Codemotion 2021)
A look inside the European Covid Green Certificate (Codemotion 2021)A look inside the European Covid Green Certificate (Codemotion 2021)
A look inside the European Covid Green Certificate (Codemotion 2021)
 
AWS Observability Made Simple
AWS Observability Made SimpleAWS Observability Made Simple
AWS Observability Made Simple
 
Semplificare l'observability per progetti Serverless
Semplificare l'observability per progetti ServerlessSemplificare l'observability per progetti Serverless
Semplificare l'observability per progetti Serverless
 
Finding a lost song with Node.js and async iterators - NodeConf Remote 2021
Finding a lost song with Node.js and async iterators - NodeConf Remote 2021Finding a lost song with Node.js and async iterators - NodeConf Remote 2021
Finding a lost song with Node.js and async iterators - NodeConf Remote 2021
 
Finding a lost song with Node.js and async iterators - EnterJS 2021
Finding a lost song with Node.js and async iterators - EnterJS 2021Finding a lost song with Node.js and async iterators - EnterJS 2021
Finding a lost song with Node.js and async iterators - EnterJS 2021
 
How to send gzipped requests with boto3
How to send gzipped requests with boto3How to send gzipped requests with boto3
How to send gzipped requests with boto3
 

Kürzlich hochgeladen

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Kürzlich hochgeladen (20)

Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 

From Node.js to Design Patterns

  • 1. From Node.js to Design Patterns Luciano Mammino @loige
  • 2. 👋 Hello, I am Luciano Cloud & Full stack software engineer nodejsdesignpatterns.com Let’s connect: 🌎 loige.co 🐦 @loige 🧳 lucianomammino
  • 3. 👇 Get the slides (and click around…) loige.link/devcast @loige
  • 4. What is Node.js Node.js is an open-source, cross-platform, JavaScript runtime environment that executes JavaScript code outside a web browser. @loige
  • 5. Node.js + JavaScript: when? ● Building for the web ○ Websites, APIs, Servers, Single Page Applications, Bots, etc… ● Command-line applications and tools ● Mobile applications (React Native, Ionic, NativeScript, etc.) ● Desktop apps (Electron) ● Embedded & IoT (Espruino, Johnny-Five) @loige
  • 6. Async I/O In JavaScript and in Node.js, input/output operations (e.g. making an HTTP request) are non-blocking. @loige
  • 7. OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("https://google.com") .build(); Response response = client.newCall(request).execute(); System.out.println(response.body().string()); System.out.println("Request completed"); A blocking HTTP request (Java) Output blocking... blocking... <google home page HTML code> Request completed Code executed “In order” @loige
  • 8. Is blocking I/O bad? It depends… If your application is I/O heavy, then you might have a problem... @loige
  • 9. Let’s make 3 requests... Req 1 Req 2 Req 3 time @loige
  • 10. You can always use threads... Req 1 Req 2 Req 3 time But threads are… Complicated Expensive A lot of idle time per thread! wait... wait... wait... @loige
  • 11. client.get('https://google.com', (err, resp) => { console.log(resp.body) } ) console.log('Request completed (?)') 👍 With Node.js async I/O Output Request “in the background” Request completed (?) <google home page HTML code> ⚠ Code executed “OUT of order” Not really completed! Non-blocking: execution continues Callback function 1 2 3 @loige
  • 12. Mental model You “just” schedule async I/O and you will get notified when the operation is completed! ● Async I/O happens in the background asynchronously ● You don’t have to manage threads to get concurrency! @loige
  • 13. Let’s do 3 requests with Async I/O “User” thread Event loop (libuv) time idle... idle... idle... Simpler code for the user Idle time only in one thread Sched. req1 Sched. req2 Sched. req3 req1 result req3 result req2 result @loige
  • 14. I am oversimplifying a bit… 😛 Watch loige.link/event-loop-what-the-heck if you want to go more in depth! @loige
  • 15. Many ways to handle async flows @loige
  • 16. Delete last reservation if confirmed ● Get a guest object from a guest id (async) ● Get the last reservation from the guest object ● Get the details of that reservation (async) ● Delete that reservation if “confirmed” (async) @loige
  • 17. Callbacks function deleteLastReservationIfConfirmed (client, guestId, cb) { client.getGuest(guestId, (err, guest) => { if (err) { return cb(err) } const lastReservation = guest.reservations.pop() if (typeof lastReservation === 'undefined') { return cb(null, false) } client.getReservation(lastReservation, (err, reservation) => { if (err) { return cb(err) } if (reservation.status === 'confirmed') { client.deleteReservation(reservation.id, (err) => { if (err) { return cb(err) } return cb(null, true) }) } }) }) } @loige
  • 18. Promises function deleteLastReservationIfConfirmed (client, guestId) { return client.getGuest(guestId) .then((guest) => { const lastReservation = guest.reservations.pop() if (typeof lastReservation !== 'undefined') { return client.getReservation(lastReservation) } }) .then((reservation) => { if (!reservation || reservation.status !== 'confirmed') { return false } return client.deleteReservation(reservation.id) }) } @loige
  • 19. Async/Await async function deleteLastReservationIfConfirmed (client, guestId) { const guest = await client.getGuest(guestId) const lastReservation = guest.reservations.pop() if (typeof lastReservation === 'undefined') { return false } const reservation = await client.getReservation(lastReservation) if (!reservation || reservation.status !== 'confirmed') { return false } return client.deleteReservation(reservation.id) } @loige
  • 20. Advantages of Async/Await ● Easier to read and reason about (“sequential flow”) ● Easier to deal with conditional async operations ● Unified error handling (you can catch both synchronous and asynchronous errors) ⚠ To fully understand async/await, you still need to understand callbacks and promises, don’t ignore them! @loige
  • 21. Other ways to handle async ● Events ● Streams ● Async iterators/generators @loige
  • 23. const guestIds = ['Peach', 'Toad', 'Mario', 'Luigi'] for (const guestId of guestIds) { await deleteLastReservationIfConfirmed(client, guestId) } Sequential execution @loige
  • 24. const guestIds = ['Peach', 'Toad', 'Mario', 'Luigi'] guestIds.forEach(async (guestId) => { await deleteLastReservationIfConfirmed(client, guestId) }) Sequential execution ⚠ Common pitfall Don’t use Array.map or Array.forEach! forEach will run all the functions without awaiting them, so all the delete invocations will happen concurrently! @loige
  • 25. const guestIds = ['Peach', 'Toad', 'Mario', 'Luigi'] await Promise.all( guestIds.map( guestId => deleteLastReservationIfConfirmed(client, guestId) ) ) Concurrent execution ⚠ Promise.all rejects as soon as one promise rejects. A failure will result in the failure of the entire operation. @loige
  • 26. const guestIds = ['Peach', 'Toad', 'Mario', 'Luigi'] const results = await Promise.allSettled( guestIds.map( guestId => deleteLastReservationIfConfirmed(client, guestId) ) ) Concurrent execution - Alternative [ { status: 'fulfilled', value: true }, { status: 'fulfilled', value: true }, { status: 'rejected', reason: Error }, { status: 'fulfilled', value: true } ] @loige
  • 27. const mapLimit = require('async/mapLimit') const guestIds = ['Peach', 'Toad', 'Mario', 'Luigi', '...'] const results = await mapLimit( guestIds, 2, // max concurrency async (guestId) => deleteLastReservationIfConfirmed(client, guestId) ) Concurrent execution - limited When you have a lot of tasks to run and what to keep limited concurrency Uses the third-party async module (npm.im/async) @loige
  • 28. Request batching Classic flow - one user HTTP Server DB /availability/v1/units @loige
  • 29. Request batching Classic flow - multiple users (no batching) HTTP Server DB /availability/v1/units /availability/v1/units /availability/v1/units @loige
  • 30. Request batching Classic flow - multiple users (with batching!) HTTP Server DB /availability/v1/units /availability/v1/units /availability/v1/units 📘 Requests in-flight pending fulfilled ⏱ /availability/v1/units ⏱ @loige
  • 31. const { createServer } = require('http') const server = createServer(async (req, res) => { const url = new URL(req.url, 'http://localhost') if (url.pathname !== '/availability/v1/units') { res.writeHead(404, 'Not found') return res.end() } const units = await getAvailableUnitsFromDb() res.writeHead(200) res.end(JSON.stringify(units)) }) server.listen(8000) The web server @loige
  • 32. let pendingRequest = null async function getAvailableUnitsFromDb () { if (pendingRequest) { console.log('batching') return pendingRequest } console.log('Getting data from db') pendingRequest = db.query('SELECT * FROM units WHERE "availability" > 0') pendingRequest.finally(() => { pendingRequest = null }) return pendingRequest } Get units from DB @loige
  • 33. Performance comparison Without batching With batching +15% throughput @loige
  • 34. In conclusion ● Node.js is a great runtime for I/O bound applications ● It’s also great for full stack web development ● The async model allows you to express concurrent computation effectively ● You still need to master callbacks, promises and async / await! ● There are many patterns that can help you out to keep your code organised and more performant. @loige
  • 35. Want to learn more? ● nodejsdesignpatterns.com - possibly a great book :) ● loige.link/javascript-mdn - mozilla guides ● eloquentjavascript.net - free e-book ● freecodecamp.org - interactive code training ● nodejs.org/api - Node.js official docs @loige