SlideShare ist ein Scribd-Unternehmen logo
1 von 59
Make your code reasonable
Jim Argeropoulos
@ExploreMqt
KEY TENET
KEY TENET
Non-Blocking
CALLBACK
fs.readFile('/etc/passwd',
function(err, data){
if (err) throw err;
console.log(data);
});
RACE STANDINGS
Read the 6 hour solo records
Read the 12 hour solo records
Read the 6 hour team records
Read the 12 hour team records
Merge the results
RACE STANDINGS
model.Team.find({group:'solo', duration:'6'}, function(err,s6){
model.Team.find({group:'solo', duration:'12'}, function(err,s12){
model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){
model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){
res.render('index', {
title: '12 Hours of Potluck',
solo6: s6,
solo12: s12,
team6: t6,
team12: t12});
});
});
});
});
CALLBACK HELL
model.Team.find({group:'solo', duration:'6'}, ['name'], function(err,s6){
model.Team.find({group:'solo', duration:'12'}, function(err,s12){
model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){
model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){
res.render('index', {
title: '12 Hours of Potluck',
solo6: s6,
solo12: s12,
team6: t6,
team12: t12});
});
});
});
});
QUERY ONE
model.Team.find({group:'solo', duration:'6'}, function(err,s6){
model.Team.find({group:'solo', duration:'12'}, function(err,s12){
model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){
model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){
res.render('index', {
title: '12 Hours of Potluck',
solo6: s6,
solo12: s12,
team6: t6,
team12: t12});
});
});
});
});
QUERY TWO
model.Team.find({group:'solo', duration:'6'}, function(err,s6){
model.Team.find({group:'solo', duration:'12'}, function(err,s12){
model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){
model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){
res.render('index', {
title: '12 Hours of Potluck',
solo6: s6,
solo12: s12,
team6: t6,
team12: t12});
});
});
});
});
QUERY THREE
model.Team.find({group:'solo', duration:'6'}, function(err,s6){
model.Team.find({group:'solo', duration:'12'}, function(err,s12){
model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){
model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){
res.render('index', {
title: '12 Hours of Potluck',
solo6: s6,
solo12: s12,
team6: t6,
team12: t12});
});
});
});
});
QUERY FOUR
model.Team.find({group:'solo', duration:'6'}, function(err,s6){
model.Team.find({group:'solo', duration:'12'}, function(err,s12){
model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){
model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){
res.render('index', {
title: '12 Hours of Potluck',
solo6: s6,
solo12: s12,
team6: t6,
team12: t12});
});
});
});
});
PROMISES
Q RSVP
ES6/2015
kew
when
vow
thenFail
bluebird
PROMISE
Pending
PROMISE
Pending
Resolved
Rejected
CONSUMER
producePromise()
.then(console.log)
.catch(console.error)
CONSUMER
producePromise()
.then(console.log)
.catch(console.error)
CONSUMER
producePromise()
.then(console.log)
.catch(console.error)
PRODUCER
function divide(numerator, denominator){
return new Promise((resolve, reject)=>{
if (denominator !== 0)
resolve(numerator / denominator)
reject('divide by zero')
})
}
PRODUCER
function divide(numerator, denominator){
return new Promise((resolve, reject)=>{
if (denominator !== 0)
resolve(numerator / denominator)
reject('divide by zero')
})
}
IN ACTION
function divide(numerator, denominator){
return new Promise((resolve, reject)=>{
if (denominator !== 0)
resolve(numerator / denominator)
reject('divide by zero')
})
}
divide(15, 3)
.then(console.log)
.catch(console.error)
IN ACTION
function divide(numerator, denominator){
return new Promise((resolve, reject)=>{
if (denominator !== 0)
resolve(numerator / denominator)
reject('divide by zero')
})
}
divide(15, 3)
.then(console.log) // 5
.catch(console.error)
IN ACTION
function divide(numerator, denominator){
return new Promise((resolve, reject)=>{
if (denominator !== 0)
resolve(numerator / denominator)
reject('divide by zero')
})
}
divide(10, 0)
.then(console.log)
.catch(console.error)
IN ACTION
function divide(numerator, denominator){
return new Promise((resolve, reject)=>{
if (denominator !== 0)
resolve(numerator / denominator)
reject('divide by zero')
})
}
divide(10, 0)
.then(console.log)
.catch(console.error) // ‘divide by zero’
ALREADY KNOWN
function divide(numerator, denominator){
return denominator ?
Promise.resolve(numerator / denominator) :
Promise.reject ('divide by zero')
}
divide(15, 3)
.then(console.log) // 5
.catch(console.error)
divide(10, 0)
.then(console.log)
.catch(console.error) // ‘divide by zero’
CALLBACK VERSION
model.Team.find({group:'solo', duration:'6'}, ['name'], function(err,s6){
model.Team.find({group:'solo', duration:'12'}, function(err,s12){
model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){
model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){
res.render('index', {
title: '12 Hours of Potluck',
solo6: s6,
solo12: s12,
team6: t6,
team12: t12});
});
});
});
});
WRAPPER
function find(team, query){
return new Promise(resolve, reject)=>{
team.find( query,
(err, docs)=>{
if(err)
reject(err)
resolve(docs)
})
})
}
ALL
var tasks = [task1, task2, task3, …]
Promise.all(tasks)
.then(results => {
//… all resolved: process results
}
.catch(err => {
// one rejected: handle err
}
RACE STANDINGS
Read the 6 hour solo records
Read the 12 hour solo records
Read the 6 hour team records
Read the 12 hour team records
Merge the results
PROMISE.ALL
Promise.all([
find(model.team, {group:'solo', duration:'6'}),
find(model.team, {group:'solo', duration:'12'}),
find(model.team, {group:{$ne:'solo'}, duration:'6'}),
find(model.team, {group:{$ne:'solo'}, duration:'12'}
])
.then(results => {
res.render('index', {
title: '12 Hours of Potluck',
solo6: results[0],
solo12: results[1],
team6: results[2],
team12: results[3]});
});
})
OPERATION VS PROCESS
PIPELINE
$ls -l | grep "Aug" | sort +4n | more
-rw-rw-rw- 1 john doc 11008 Aug 6 14:10 ch02
-rw-rw-rw- 1 john doc 8515 Aug 6 15:30 ch07
-rw-rw-r-- 1 john doc 2488 Aug 15 10:51 intro
-rw-rw-r-- 1 carol doc 1605 Aug 23 07:35 macros
$
CHAINING
Promise.resolve(10)
.then(n => 2 * n) // <= NOT a promise
.then(console.log) // 20
CHAINING
function rejectN(n){
Promise.reject(’just because’)
}
Promise.resolve(10)
.then(n => 2 * n)
.then(rejectN)
.then(n => 3 * n)
.then(console.log)
.catch(console.error)
MORE DATA?
Promise.resolve(10)
.then(divide)
.then(console.log)
What if you need a second parameter?
ADD
function add(x, y){
return x + y
}
OVERLOAD
function add(x, y){
return x + y
}
var add5(y){
return add(5, y)
}
console.log(add5(1)) // 6
OVERLOAD
function add(x, y){
return x + y
}
var add5(y){
return add(5, y)
}
var add6(y){
return add(6, y)
}
BIND
function add(x, y){
return x + y
}
var add5 = add.bind(undefined, 5)
console.log(add5(1)) // 6
PARTIAL
var _ = require(‘lodash’)
//could also use ramda
function add(x, y){
return x + y
}
var add5 = _.partial(add, 5)
console.log(add5(1)) // 6
PARTIAL RIGHT
var _ = require(‘lodash’)
function add(x, y){
console.log(‘x’, x) // x 1
console.log(‘y’, y) // y 5
return x + y
}
var add5 = _.partialRight(add, 5)
PIPELINE
$ls -l | grep "Aug" | sort +4n | more
-rw-rw-rw- 1 john doc 11008 Aug 6 14:10 ch02
-rw-rw-rw- 1 john doc 8515 Aug 6 15:30 ch07
-rw-rw-r-- 1 john doc 2488 Aug 15 10:51 intro
-rw-rw-r-- 1 carol doc 1605 Aug 23 07:35 macros
$
var _ = require(‘lodash')
function readPeopleFromFile(){
Promise.resolve([
{name: 'Risto', age: 6 },
{name: 'Niilo', age: 8 },
{name: 'Edla', age: 12 }])
}
}
readPeopleFromFile()
//filter the people younger than 10,
//_.filter(collection, [predicate=_.identity], [thisArg])
//order by name
//_.sortBy(collection, [iteratee=_.identity], [thisArg])
PARTIAL IN ACTION
PARTIAL IN ACTION
var _ = require('lodash')
function readPeopleFromFile(){
Promise.resolve([
{name: 'Risto', age: 6 },
{name: 'Niilo', age: 8 },
{name: 'Edla', age: 12 }])
}
}
readPeopleFromFile()
.then(_.partialRight(_.filter, p => p.age < 10))
.then(_.partialRight(_.sortBy, 'name'))
.then(console.log)
//[{name: 'Niilo', age: 8 },
// {name: 'Risto', age: 6 }]
NOT JUST FOR PROMISES
SHORT HAND
var mock{
readPeopleFromFile: () => Promise.resolve([]),
render: () => {}
}
inject = _.partial(_.extend, {}, mock)
it('should not use the file system’,() => {
readKids(inject({
readPeopleFromFile: () => {
Promise.resolve([
{name: 'Risto', age: 6 },
{name: 'Niilo', age: 8 },
{name: 'Edla', age: 12 }])
}
}
}))
.then(result => {
result[0].name.should.equal('Niilo')
})
})
SEPTEMBER 8
SEPTEMBER 8
Node 4.0 Now with Arrow Functions!
Arrow Functions > partialRight
PARTIAL IN ACTION
var _ = require('lodash')
function readPeopleFromFile(){
Promise.resolve([
{name: 'Risto', age: 6 },
{name: 'Niilo', age: 8 },
{name: 'Edla', age: 12 }])
}
}
readPeopleFromFile()
.then(_.partialRight(_.filter, p => p.age < 10))
.then(_.partialRight(_.sortBy, 'name'))
.then(console.log)
//[{name: 'Niilo', age: 8 },
// {name: 'Risto', age: 6 }]
var _ = require('lodash')
function readPeopleFromFile(){
Promise.resolve([
{name: 'Risto', age: 6 },
{name: 'Niilo', age: 8 },
{name: 'Edla', age: 12 }])
}
}
readPeopleFromFile()
.then(_.partialRight(_.filter, p => p.age < 10))
.then(_.partialRight(_.sortBy, 'name'))
.then(console.log)
//[{name: 'Niilo', age: 8 },
// {name: 'Risto', age: 6 }]
PARTIAL IN ACTION
CLOSURE
var _ = require('lodash')
Promise.resolve([
{name: 'Risto', age: 6 },
{name: 'Niilo', age: 8 },
{name: 'Edla', age: 12 }])
.then(people => _.filter(people, p => p.age < 10))
.then(people => _.sortBy(people, 'name'))
.then(console.log)
//[{name: 'Niilo', age: 8 },
// {name: 'Risto', age: 6 }]
BEST PRACTICES
Promise.resolve(10)
.then(n => 2 * n)
.then(largeBusinessRule)
.then(console.log)
BEST PRACTICES
validateParams(req) // <= not blocking
.then(blockingTask)
.then(parseResults)
.then(pageResults)
SUMMARY
What is a Promise
Consume a promise
Produce a promise
Manage multiple blocking tasks with promises
Chain small tasks
Partial application
Closure
QUESTIONS
CONTACT
Jim Argeropoulos
tenholeharp@gmail.com
@ExploreMqt
ASYNC SOLUTION
async.parallel([
cb => { model.Team.find({group:'solo', duration:'6'}, cb)},
cb => { model.Team.find({group:'solo', duration:'12'}, cb)},
cb => { model.Team.find({group:{$ne:'solo'}, duration:'6'}, cb)},
cb => { model.Team.find({group:{$ne:'solo'}, duration:'12'}, cb)},
],
results => {
res.render('index', {
title: '12 Hours of Potluck',
solo6: results[0],
solo12: results[1],
team6: results[2],
team12: results[3]});
}
)

Weitere ähnliche Inhalte

Was ist angesagt?

Seistech SQL code
Seistech SQL codeSeistech SQL code
Seistech SQL codeSimon Hoyle
 
Parsing with Perl6 Grammars
Parsing with Perl6 GrammarsParsing with Perl6 Grammars
Parsing with Perl6 Grammarsabrummett
 
Innovative Specifications for Better Performance Logging and Monitoring
Innovative Specifications for Better Performance Logging and MonitoringInnovative Specifications for Better Performance Logging and Monitoring
Innovative Specifications for Better Performance Logging and MonitoringCary Millsap
 
The Ring programming language version 1.7 book - Part 12 of 196
The Ring programming language version 1.7 book - Part 12 of 196The Ring programming language version 1.7 book - Part 12 of 196
The Ring programming language version 1.7 book - Part 12 of 196Mahmoud Samir Fayed
 
Recentrer l'intelligence artificielle sur les connaissances
Recentrer l'intelligence artificielle sur les connaissancesRecentrer l'intelligence artificielle sur les connaissances
Recentrer l'intelligence artificielle sur les connaissancesMathieu d'Aquin
 
The Ring programming language version 1.6 book - Part 11 of 189
The Ring programming language version 1.6 book - Part 11 of 189The Ring programming language version 1.6 book - Part 11 of 189
The Ring programming language version 1.6 book - Part 11 of 189Mahmoud Samir Fayed
 
Cypher inside out: Como a linguagem de pesquisas em grafo do Neo4j foi constr...
Cypher inside out: Como a linguagem de pesquisas em grafo do Neo4j foi constr...Cypher inside out: Como a linguagem de pesquisas em grafo do Neo4j foi constr...
Cypher inside out: Como a linguagem de pesquisas em grafo do Neo4j foi constr...adrianoalmeida7
 
Stored Procedures and MUMPS for DivConq
 Stored Procedures and  MUMPS for DivConq  Stored Procedures and  MUMPS for DivConq
Stored Procedures and MUMPS for DivConq eTimeline, LLC
 
Marimba - Ein MapReduce-basiertes Programmiermodell für selbstwartbare Aggreg...
Marimba - Ein MapReduce-basiertes Programmiermodell für selbstwartbare Aggreg...Marimba - Ein MapReduce-basiertes Programmiermodell für selbstwartbare Aggreg...
Marimba - Ein MapReduce-basiertes Programmiermodell für selbstwartbare Aggreg...Johannes Schildgen
 
PHP and MySQL Tips and tricks, DC 2007
PHP and MySQL Tips and tricks, DC 2007PHP and MySQL Tips and tricks, DC 2007
PHP and MySQL Tips and tricks, DC 2007Damien Seguy
 
Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...
Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...
Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...Johannes Schildgen
 

Was ist angesagt? (19)

Seistech SQL code
Seistech SQL codeSeistech SQL code
Seistech SQL code
 
Five
FiveFive
Five
 
Unit testing pig
Unit testing pigUnit testing pig
Unit testing pig
 
Materi my sql part 1
Materi my sql part 1Materi my sql part 1
Materi my sql part 1
 
Parsing with Perl6 Grammars
Parsing with Perl6 GrammarsParsing with Perl6 Grammars
Parsing with Perl6 Grammars
 
Innovative Specifications for Better Performance Logging and Monitoring
Innovative Specifications for Better Performance Logging and MonitoringInnovative Specifications for Better Performance Logging and Monitoring
Innovative Specifications for Better Performance Logging and Monitoring
 
PHP 5.4
PHP 5.4PHP 5.4
PHP 5.4
 
The Ring programming language version 1.7 book - Part 12 of 196
The Ring programming language version 1.7 book - Part 12 of 196The Ring programming language version 1.7 book - Part 12 of 196
The Ring programming language version 1.7 book - Part 12 of 196
 
Tugas praktikum smbd
Tugas praktikum smbdTugas praktikum smbd
Tugas praktikum smbd
 
Recentrer l'intelligence artificielle sur les connaissances
Recentrer l'intelligence artificielle sur les connaissancesRecentrer l'intelligence artificielle sur les connaissances
Recentrer l'intelligence artificielle sur les connaissances
 
Into Clojure
Into ClojureInto Clojure
Into Clojure
 
CoffeeScript
CoffeeScriptCoffeeScript
CoffeeScript
 
The Ring programming language version 1.6 book - Part 11 of 189
The Ring programming language version 1.6 book - Part 11 of 189The Ring programming language version 1.6 book - Part 11 of 189
The Ring programming language version 1.6 book - Part 11 of 189
 
Cypher inside out: Como a linguagem de pesquisas em grafo do Neo4j foi constr...
Cypher inside out: Como a linguagem de pesquisas em grafo do Neo4j foi constr...Cypher inside out: Como a linguagem de pesquisas em grafo do Neo4j foi constr...
Cypher inside out: Como a linguagem de pesquisas em grafo do Neo4j foi constr...
 
Stored Procedures and MUMPS for DivConq
 Stored Procedures and  MUMPS for DivConq  Stored Procedures and  MUMPS for DivConq
Stored Procedures and MUMPS for DivConq
 
Marimba - Ein MapReduce-basiertes Programmiermodell für selbstwartbare Aggreg...
Marimba - Ein MapReduce-basiertes Programmiermodell für selbstwartbare Aggreg...Marimba - Ein MapReduce-basiertes Programmiermodell für selbstwartbare Aggreg...
Marimba - Ein MapReduce-basiertes Programmiermodell für selbstwartbare Aggreg...
 
PHP and MySQL Tips and tricks, DC 2007
PHP and MySQL Tips and tricks, DC 2007PHP and MySQL Tips and tricks, DC 2007
PHP and MySQL Tips and tricks, DC 2007
 
veracruz
veracruzveracruz
veracruz
 
Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...
Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...
Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...
 

Ähnlich wie Promise it's partial

Perl6 a whistle stop tour
Perl6 a whistle stop tourPerl6 a whistle stop tour
Perl6 a whistle stop tourSimon Proctor
 
Perl6 a whistle stop tour
Perl6 a whistle stop tourPerl6 a whistle stop tour
Perl6 a whistle stop tourSimon Proctor
 
ESNext for humans - LvivJS 16 August 2014
ESNext for humans - LvivJS 16 August 2014ESNext for humans - LvivJS 16 August 2014
ESNext for humans - LvivJS 16 August 2014Jan Jongboom
 
How to write code you won't hate tomorrow
How to write code you won't hate tomorrowHow to write code you won't hate tomorrow
How to write code you won't hate tomorrowPete McFarlane
 
Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldBTI360
 
{:from => 'Java', :to => 'Ruby'}
{:from => 'Java', :to => 'Ruby'}{:from => 'Java', :to => 'Ruby'}
{:from => 'Java', :to => 'Ruby'}Shintaro Kakutani
 
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+ConFoo
 
R57shell
R57shellR57shell
R57shellady36
 
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
JDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation streamJDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation stream
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation streamRuslan Shevchenko
 
Adding ES6 to Your Developer Toolbox
Adding ES6 to Your Developer ToolboxAdding ES6 to Your Developer Toolbox
Adding ES6 to Your Developer ToolboxJeff Strauss
 
Alexei shilov 2010 rit-rakudo
Alexei shilov 2010 rit-rakudoAlexei shilov 2010 rit-rakudo
Alexei shilov 2010 rit-rakudorit2010
 
Jonathan Worthington – Perl 2010 Rit Rakudo
Jonathan Worthington – Perl 2010 Rit RakudoJonathan Worthington – Perl 2010 Rit Rakudo
Jonathan Worthington – Perl 2010 Rit Rakudorit2010
 
More than syntax
More than syntaxMore than syntax
More than syntaxWooga
 
Reiterating JavaScript & Node.js iterators
Reiterating JavaScript & Node.js iteratorsReiterating JavaScript & Node.js iterators
Reiterating JavaScript & Node.js iteratorsLuciano Mammino
 
Patterns in Terraform 12+13: Data, Transformations and Resources
Patterns in Terraform 12+13: Data, Transformations and ResourcesPatterns in Terraform 12+13: Data, Transformations and Resources
Patterns in Terraform 12+13: Data, Transformations and ResourcesKatie Reese
 
Python and rust 2018 pythonkorea jihun
Python and rust 2018 pythonkorea jihunPython and rust 2018 pythonkorea jihun
Python and rust 2018 pythonkorea jihunJIHUN KIM
 
Purely functional data structures
Purely functional data structuresPurely functional data structures
Purely functional data structuresTomasz Kaczmarzyk
 
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Suyeol Jeon
 

Ähnlich wie Promise it's partial (20)

Perl6 a whistle stop tour
Perl6 a whistle stop tourPerl6 a whistle stop tour
Perl6 a whistle stop tour
 
Perl6 a whistle stop tour
Perl6 a whistle stop tourPerl6 a whistle stop tour
Perl6 a whistle stop tour
 
ESNext for humans - LvivJS 16 August 2014
ESNext for humans - LvivJS 16 August 2014ESNext for humans - LvivJS 16 August 2014
ESNext for humans - LvivJS 16 August 2014
 
Exploring ES6
Exploring ES6Exploring ES6
Exploring ES6
 
How to write code you won't hate tomorrow
How to write code you won't hate tomorrowHow to write code you won't hate tomorrow
How to write code you won't hate tomorrow
 
Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 World
 
{:from => 'Java', :to => 'Ruby'}
{:from => 'Java', :to => 'Ruby'}{:from => 'Java', :to => 'Ruby'}
{:from => 'Java', :to => 'Ruby'}
 
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
 
Agile database access with CakePHP 3
Agile database access with CakePHP 3Agile database access with CakePHP 3
Agile database access with CakePHP 3
 
R57shell
R57shellR57shell
R57shell
 
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
JDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation streamJDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation stream
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
 
Adding ES6 to Your Developer Toolbox
Adding ES6 to Your Developer ToolboxAdding ES6 to Your Developer Toolbox
Adding ES6 to Your Developer Toolbox
 
Alexei shilov 2010 rit-rakudo
Alexei shilov 2010 rit-rakudoAlexei shilov 2010 rit-rakudo
Alexei shilov 2010 rit-rakudo
 
Jonathan Worthington – Perl 2010 Rit Rakudo
Jonathan Worthington – Perl 2010 Rit RakudoJonathan Worthington – Perl 2010 Rit Rakudo
Jonathan Worthington – Perl 2010 Rit Rakudo
 
More than syntax
More than syntaxMore than syntax
More than syntax
 
Reiterating JavaScript & Node.js iterators
Reiterating JavaScript & Node.js iteratorsReiterating JavaScript & Node.js iterators
Reiterating JavaScript & Node.js iterators
 
Patterns in Terraform 12+13: Data, Transformations and Resources
Patterns in Terraform 12+13: Data, Transformations and ResourcesPatterns in Terraform 12+13: Data, Transformations and Resources
Patterns in Terraform 12+13: Data, Transformations and Resources
 
Python and rust 2018 pythonkorea jihun
Python and rust 2018 pythonkorea jihunPython and rust 2018 pythonkorea jihun
Python and rust 2018 pythonkorea jihun
 
Purely functional data structures
Purely functional data structuresPurely functional data structures
Purely functional data structures
 
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
 

Kürzlich hochgeladen

Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Cizo Technology Services
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalLionel Briand
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf31events.com
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commercemanigoyal112
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Natan Silnitsky
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringHironori Washizaki
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsSafe Software
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...confluent
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 
cpct NetworkING BASICS AND NETWORK TOOL.ppt
cpct NetworkING BASICS AND NETWORK TOOL.pptcpct NetworkING BASICS AND NETWORK TOOL.ppt
cpct NetworkING BASICS AND NETWORK TOOL.pptrcbcrtm
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfDrew Moseley
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 

Kürzlich hochgeladen (20)

Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive Goal
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commerce
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Odoo Development Company in India | Devintelle Consulting Service
Odoo Development Company in India | Devintelle Consulting ServiceOdoo Development Company in India | Devintelle Consulting Service
Odoo Development Company in India | Devintelle Consulting Service
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their Engineering
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data Streams
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 
cpct NetworkING BASICS AND NETWORK TOOL.ppt
cpct NetworkING BASICS AND NETWORK TOOL.pptcpct NetworkING BASICS AND NETWORK TOOL.ppt
cpct NetworkING BASICS AND NETWORK TOOL.ppt
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdf
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 

Promise it's partial

  • 1. Make your code reasonable Jim Argeropoulos @ExploreMqt
  • 2.
  • 6. RACE STANDINGS Read the 6 hour solo records Read the 12 hour solo records Read the 6 hour team records Read the 12 hour team records Merge the results
  • 7. RACE STANDINGS model.Team.find({group:'solo', duration:'6'}, function(err,s6){ model.Team.find({group:'solo', duration:'12'}, function(err,s12){ model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){ model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){ res.render('index', { title: '12 Hours of Potluck', solo6: s6, solo12: s12, team6: t6, team12: t12}); }); }); }); });
  • 8. CALLBACK HELL model.Team.find({group:'solo', duration:'6'}, ['name'], function(err,s6){ model.Team.find({group:'solo', duration:'12'}, function(err,s12){ model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){ model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){ res.render('index', { title: '12 Hours of Potluck', solo6: s6, solo12: s12, team6: t6, team12: t12}); }); }); }); });
  • 9. QUERY ONE model.Team.find({group:'solo', duration:'6'}, function(err,s6){ model.Team.find({group:'solo', duration:'12'}, function(err,s12){ model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){ model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){ res.render('index', { title: '12 Hours of Potluck', solo6: s6, solo12: s12, team6: t6, team12: t12}); }); }); }); });
  • 10. QUERY TWO model.Team.find({group:'solo', duration:'6'}, function(err,s6){ model.Team.find({group:'solo', duration:'12'}, function(err,s12){ model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){ model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){ res.render('index', { title: '12 Hours of Potluck', solo6: s6, solo12: s12, team6: t6, team12: t12}); }); }); }); });
  • 11. QUERY THREE model.Team.find({group:'solo', duration:'6'}, function(err,s6){ model.Team.find({group:'solo', duration:'12'}, function(err,s12){ model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){ model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){ res.render('index', { title: '12 Hours of Potluck', solo6: s6, solo12: s12, team6: t6, team12: t12}); }); }); }); });
  • 12. QUERY FOUR model.Team.find({group:'solo', duration:'6'}, function(err,s6){ model.Team.find({group:'solo', duration:'12'}, function(err,s12){ model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){ model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){ res.render('index', { title: '12 Hours of Potluck', solo6: s6, solo12: s12, team6: t6, team12: t12}); }); }); }); });
  • 19. PRODUCER function divide(numerator, denominator){ return new Promise((resolve, reject)=>{ if (denominator !== 0) resolve(numerator / denominator) reject('divide by zero') }) }
  • 20. PRODUCER function divide(numerator, denominator){ return new Promise((resolve, reject)=>{ if (denominator !== 0) resolve(numerator / denominator) reject('divide by zero') }) }
  • 21. IN ACTION function divide(numerator, denominator){ return new Promise((resolve, reject)=>{ if (denominator !== 0) resolve(numerator / denominator) reject('divide by zero') }) } divide(15, 3) .then(console.log) .catch(console.error)
  • 22. IN ACTION function divide(numerator, denominator){ return new Promise((resolve, reject)=>{ if (denominator !== 0) resolve(numerator / denominator) reject('divide by zero') }) } divide(15, 3) .then(console.log) // 5 .catch(console.error)
  • 23. IN ACTION function divide(numerator, denominator){ return new Promise((resolve, reject)=>{ if (denominator !== 0) resolve(numerator / denominator) reject('divide by zero') }) } divide(10, 0) .then(console.log) .catch(console.error)
  • 24. IN ACTION function divide(numerator, denominator){ return new Promise((resolve, reject)=>{ if (denominator !== 0) resolve(numerator / denominator) reject('divide by zero') }) } divide(10, 0) .then(console.log) .catch(console.error) // ‘divide by zero’
  • 25. ALREADY KNOWN function divide(numerator, denominator){ return denominator ? Promise.resolve(numerator / denominator) : Promise.reject ('divide by zero') } divide(15, 3) .then(console.log) // 5 .catch(console.error) divide(10, 0) .then(console.log) .catch(console.error) // ‘divide by zero’
  • 26. CALLBACK VERSION model.Team.find({group:'solo', duration:'6'}, ['name'], function(err,s6){ model.Team.find({group:'solo', duration:'12'}, function(err,s12){ model.Team.find({group:{$ne:'solo'}, duration:'6'}, function(err,t6){ model.Team.find({group:{$ne:'solo'}, duration:'12'}, function(err,t12){ res.render('index', { title: '12 Hours of Potluck', solo6: s6, solo12: s12, team6: t6, team12: t12}); }); }); }); });
  • 27. WRAPPER function find(team, query){ return new Promise(resolve, reject)=>{ team.find( query, (err, docs)=>{ if(err) reject(err) resolve(docs) }) }) }
  • 28. ALL var tasks = [task1, task2, task3, …] Promise.all(tasks) .then(results => { //… all resolved: process results } .catch(err => { // one rejected: handle err }
  • 29. RACE STANDINGS Read the 6 hour solo records Read the 12 hour solo records Read the 6 hour team records Read the 12 hour team records Merge the results
  • 30. PROMISE.ALL Promise.all([ find(model.team, {group:'solo', duration:'6'}), find(model.team, {group:'solo', duration:'12'}), find(model.team, {group:{$ne:'solo'}, duration:'6'}), find(model.team, {group:{$ne:'solo'}, duration:'12'} ]) .then(results => { res.render('index', { title: '12 Hours of Potluck', solo6: results[0], solo12: results[1], team6: results[2], team12: results[3]}); }); })
  • 32. PIPELINE $ls -l | grep "Aug" | sort +4n | more -rw-rw-rw- 1 john doc 11008 Aug 6 14:10 ch02 -rw-rw-rw- 1 john doc 8515 Aug 6 15:30 ch07 -rw-rw-r-- 1 john doc 2488 Aug 15 10:51 intro -rw-rw-r-- 1 carol doc 1605 Aug 23 07:35 macros $
  • 33. CHAINING Promise.resolve(10) .then(n => 2 * n) // <= NOT a promise .then(console.log) // 20
  • 34. CHAINING function rejectN(n){ Promise.reject(’just because’) } Promise.resolve(10) .then(n => 2 * n) .then(rejectN) .then(n => 3 * n) .then(console.log) .catch(console.error)
  • 37. OVERLOAD function add(x, y){ return x + y } var add5(y){ return add(5, y) } console.log(add5(1)) // 6
  • 38. OVERLOAD function add(x, y){ return x + y } var add5(y){ return add(5, y) } var add6(y){ return add(6, y) }
  • 39. BIND function add(x, y){ return x + y } var add5 = add.bind(undefined, 5) console.log(add5(1)) // 6
  • 40. PARTIAL var _ = require(‘lodash’) //could also use ramda function add(x, y){ return x + y } var add5 = _.partial(add, 5) console.log(add5(1)) // 6
  • 41. PARTIAL RIGHT var _ = require(‘lodash’) function add(x, y){ console.log(‘x’, x) // x 1 console.log(‘y’, y) // y 5 return x + y } var add5 = _.partialRight(add, 5)
  • 42.
  • 43. PIPELINE $ls -l | grep "Aug" | sort +4n | more -rw-rw-rw- 1 john doc 11008 Aug 6 14:10 ch02 -rw-rw-rw- 1 john doc 8515 Aug 6 15:30 ch07 -rw-rw-r-- 1 john doc 2488 Aug 15 10:51 intro -rw-rw-r-- 1 carol doc 1605 Aug 23 07:35 macros $
  • 44. var _ = require(‘lodash') function readPeopleFromFile(){ Promise.resolve([ {name: 'Risto', age: 6 }, {name: 'Niilo', age: 8 }, {name: 'Edla', age: 12 }]) } } readPeopleFromFile() //filter the people younger than 10, //_.filter(collection, [predicate=_.identity], [thisArg]) //order by name //_.sortBy(collection, [iteratee=_.identity], [thisArg]) PARTIAL IN ACTION
  • 45. PARTIAL IN ACTION var _ = require('lodash') function readPeopleFromFile(){ Promise.resolve([ {name: 'Risto', age: 6 }, {name: 'Niilo', age: 8 }, {name: 'Edla', age: 12 }]) } } readPeopleFromFile() .then(_.partialRight(_.filter, p => p.age < 10)) .then(_.partialRight(_.sortBy, 'name')) .then(console.log) //[{name: 'Niilo', age: 8 }, // {name: 'Risto', age: 6 }]
  • 46. NOT JUST FOR PROMISES
  • 47. SHORT HAND var mock{ readPeopleFromFile: () => Promise.resolve([]), render: () => {} } inject = _.partial(_.extend, {}, mock) it('should not use the file system’,() => { readKids(inject({ readPeopleFromFile: () => { Promise.resolve([ {name: 'Risto', age: 6 }, {name: 'Niilo', age: 8 }, {name: 'Edla', age: 12 }]) } } })) .then(result => { result[0].name.should.equal('Niilo') }) })
  • 49. SEPTEMBER 8 Node 4.0 Now with Arrow Functions!
  • 50. Arrow Functions > partialRight
  • 51. PARTIAL IN ACTION var _ = require('lodash') function readPeopleFromFile(){ Promise.resolve([ {name: 'Risto', age: 6 }, {name: 'Niilo', age: 8 }, {name: 'Edla', age: 12 }]) } } readPeopleFromFile() .then(_.partialRight(_.filter, p => p.age < 10)) .then(_.partialRight(_.sortBy, 'name')) .then(console.log) //[{name: 'Niilo', age: 8 }, // {name: 'Risto', age: 6 }]
  • 52. var _ = require('lodash') function readPeopleFromFile(){ Promise.resolve([ {name: 'Risto', age: 6 }, {name: 'Niilo', age: 8 }, {name: 'Edla', age: 12 }]) } } readPeopleFromFile() .then(_.partialRight(_.filter, p => p.age < 10)) .then(_.partialRight(_.sortBy, 'name')) .then(console.log) //[{name: 'Niilo', age: 8 }, // {name: 'Risto', age: 6 }] PARTIAL IN ACTION
  • 53. CLOSURE var _ = require('lodash') Promise.resolve([ {name: 'Risto', age: 6 }, {name: 'Niilo', age: 8 }, {name: 'Edla', age: 12 }]) .then(people => _.filter(people, p => p.age < 10)) .then(people => _.sortBy(people, 'name')) .then(console.log) //[{name: 'Niilo', age: 8 }, // {name: 'Risto', age: 6 }]
  • 54. BEST PRACTICES Promise.resolve(10) .then(n => 2 * n) .then(largeBusinessRule) .then(console.log)
  • 55. BEST PRACTICES validateParams(req) // <= not blocking .then(blockingTask) .then(parseResults) .then(pageResults)
  • 56. SUMMARY What is a Promise Consume a promise Produce a promise Manage multiple blocking tasks with promises Chain small tasks Partial application Closure
  • 59. ASYNC SOLUTION async.parallel([ cb => { model.Team.find({group:'solo', duration:'6'}, cb)}, cb => { model.Team.find({group:'solo', duration:'12'}, cb)}, cb => { model.Team.find({group:{$ne:'solo'}, duration:'6'}, cb)}, cb => { model.Team.find({group:{$ne:'solo'}, duration:'12'}, cb)}, ], results => { res.render('index', { title: '12 Hours of Potluck', solo6: results[0], solo12: results[1], team6: results[2], team12: results[3]}); } )

Hinweis der Redaktion

  1. How many of you have written a node program? How many of you write JavaScript for the front end? For those of you who are daily users of JavaScript, we are going to start slow and cover what might be some boring details, but as we close in on the end of the session, we will be looking at some functional programming techniques. My hope no matter your experience level, you will want to go home and play with some of these ideas.
  2. What is a key tenant of Node which makes it different from many programming models?
  3. Non blocking or in maybe a more common parlance asynchronous. In Node, many operations will not complete right away. Instead of waiting for them to complete, you supply a callback and the system hooks you in when the results are ready.
  4. Here is a straight forward non-blocking call withe a callback. This example is from the fs docs. You ask for the contents of the password file to be read. When the data has been read, or an error occurs, the function you supplied as the second parameter is called. In a simple example it looks straight forward. But lets take a case where a few more things need to be done.
  5. Here is a set of steps for my very first node app a couple years ago. I was helping a local mountain bike race track riders. I needed to read the results for each race category and then stitch the data together. Notice that it is rather plain and straight forward
  6. I know you can’t read this code. The first thing I want you to see is that the code is not like the requirements. The requirements were a simple list of tasks.
  7. What we have here is a deeply nested set of operations and callbacks. In the first callback you initiate the second step, in the second you initiate the third… etc Heaven forbid you did like I did the first time and don’t nest the steps. In that case you get no data when you merge the results. I won’t pretend that I’m the first to suggest that this is a problem.
  8. Lets spend a little time identifying the important details
  9. Is it impossible to make out what this code does? No. Is there a lot of boiler plate? Oh yeah I won’t pretend that I’m the first to suggest that this is a problem. Far from it. There are multiple ways to resolve callback hell. Today I want to show you how to do it with promises. But before we get to showing that solution, lets delve into what a promise is.
  10. A promise isn’t a new idea. Promise libraries have existed for a few years. This is a smattering of the available promise implementations. What is new is that ES6/2015 has an implementation. This implementation is one of the ES6 features which is available out of the box in Node. You may have encountered the prior libraries, but we want to learn the new standard.
  11. A promise is a container for a future value. A promise is an object which can only be in one of three states. It’s initial state is pending.
  12. It’s state can change to either resolved or rejected, and once it changes from pending, it cannot change a second time.
  13. As a consumer of a promise, you have two hooks: then and catch. These two functions are your means to extract that future value when it becomes available. Your handler will not be called until the promise moves out of the pending state.
  14. If the promise is resolved, the handler given to then will be called.
  15. If the promise is rejected, the handler given to catch will be called. If the promise has already been resolved or rejected before you call then or catch, your handler will be called immediately.
  16. As a promise producer, instead of taking a callback, you define a function to return a promise. The promise constructor takes a function. The parameters to this function are resolve and reject. You call resolve or reject to move the promise out of the pending state.
  17. In this case there is no blocking operation and the promise will just be for some structured error handling. If the denominator is zero we reject the promise and indicate it was a divide by zero. Otherwise, we call resolve with the answer
  18. Alright, lets call our divide function. What do you think the result will be? Show of hands: Who thinks the result will be 5? Who thinks the result will be ‘divide by zero’? <Ask why they though this>
  19. The answer is 5 because after the promise has changed from the pending state, it’s value can never be changed.
  20. Okay, how about calling divide with 10 and zero?
  21. Yes ‘divide by zero’ is the answer The syntax used here is the full complete syntax. It is the syntax you must use when performing a blocking action. However, there are some shorthand helper methods you can use in some scenarios too.
  22. In our divide example, the answer is already known. There is no requirement that you can only use promises when there is an asynchronous operation involved. If you are implementing a function where the answer can be obtained without a blocking operation, you can use some short hand notation. You can use Promise’s resolve and reject functions directly. I don’t know what your preferences are, but I’d much prefer to write this variant when I have the chance. The key is that you cannot use them with blocking operations.
  23. Okay, let’s take the theory and sample work we have done so far and begin to convert the race standings. The first thing we need to do is create a way to convert from the mongoose callback style to something that returns a promise
  24. First we need a helper method to convert our mongo queries to return promises. Note the real work happens in the callback
  25. Next we need another promise function: all. All takes an array of promises and returns a promise. The returned promise is resolved when all the tasks resolve. It could be rejected if one of the tasks are rejected.
  26. We are now ready to solve callback hell with promises. In case you have forgotten, here is our spec. Four queries and some work to process the results.
  27. With this solution we no longer have the deeply nested callbacks and it is much easier to reason about the code. It looks much more like our spec Personally, what I like about this version is how much easier it is to see the details of each query.
  28. So far everything that we have looked at has involved a single then. However, it is not uncommon to need to do more than one thing to accomplish a task. So lets look at yet another way to use promises.
  29. I admit. I’m a latecomer to BASH, but I’ve learned to love it’s penchant for solving problems with creating a pipeline of small operations. You may not be familiar with bash. Just in case, here is what this line says. *list all the files in the directory. *filter out the lines that don’t contain Aug in them *sort the remaining lines using the 5th column *and finally page the results Each one of these commands do a small part and put together do a complex task. Often an asynchronous operation might be one of many that you need to perform in order to accomplish a task. One of the features I love about promises is how they support and encourage this pipelining of small tasks.
  30. Here is a very simple example of chaining. An operation that produces a promise and then two tasks that operate on the promise value Note that the first then returns plain old JavaScript. It does not return a promise. And that is just fine. This was not something that was immediately obvious to me, but it is very handy.
  31. Here is a longer example, but note what happens in the middle, there is an operation that causes a promise to be rejected. The third and the fourth then conditions are skipped and the handler to catch is executed. Much like try/catch you can use this to really clean up your error handling.
  32. If we wrote this code to use the previously defined divide function, we would alway have the promise rejected. The handler you supply to then is only given one parameter when the promise is resolved. What do you do when the next operation you need to perform needs more than one parameter? (closure, partial application) To answer this question, lets take a side trip away from promises for a bit.
  33. Here is a simple function. You all know what it’s going to do. But what change do you make if I said that you needed come up with a way to always to add 5 to a number?
  34. Maybe this is what you might do. And it works too!
  35. What if I said you needed to support adding 6 as well as 5. This solution quickly starts to become less DRY. It’s also very static. There are many times the data you bind is generated at runtime. In that case this method won’t work. What we have here is a manual case of a functional programming technique called partial application. The good news is that there are libraries that can do the heavy lifting.
  36. You could use the built in bind, but it is verbose and you can only bind the parameters on the left hand side. Which can be a problem.
  37. Using lodash or ramda is my preferred solution. Both provide a partial function. The first parameter for partial is the function you would like to overload. After that is a variable argument list. In this case we are only affixing one parameter, but there are no restrictions on the number. It could even be all of the parameters a function takes. I mentioned that one downside of bind is that you can only bind the left hand parameter. X in this case. But what if the parameter you want to bind is on the right end of the parameter list?
  38. This is the reason I like lodash and ramda. Not only do they provide a partial function, they also provide partialRight. Here we have asked lodash to bind the value supplied to the right most parameter, or y in our case.
  39. You might be thinking this… bear with me!
  40. We started out this section on chaining by talking about a set of small bash commands piped together to make a powerful compound command. Let’s put the things we’ve learned together…
  41. Lets imagine that instead of resolving an array of people, you are reading a file containing people. After you get the data back, you need to apply a filter and the order the data. Not all that different from our bash command. There are any number of ways to accomplish this task, but lets make use of lodash’s filter and sortBy functions. Note that the first parameter of both filter and sortBy is the collection to work with. That collection is the data coming from our promise. That means if we want to chain the filter and sortBy, we’ll have to use partialRight
  42. Partial application can be used in many places, not just with chaining promises.
  43. When you are testing your code, you often want to use dependency injection to insert some alternate behavior. In this case we do not want our readKids function to access the file system. So we use DI to override that in test scenarios. Our mock resolves an empty array. But then in each test we can provide yet another implementation. Using partial application makes for more compact and explicit code
  44. Something important happened on September 8th. Does anyone have a guess what that might be?
  45. Node didn’t support arrow functions without flags until Node 4. Now I know that there are nearly 8 weeks between Node 4 and now, but it wasn’t until last week that I had a revelation.
  46. For months I’ve been complaining about this kind of code to my friend Darren. The meat of what is being done is kind of hidden at the end. Buried in boiler plate. Somehow it takes more effort than I want to read it.
  47. The _.partialRight is kind of boiler plate. In addition carries a level of implicit knowledge
  48. Hands down in this example, arrow functions and closure wins. It is simpler and more explicit. However, I still have times when I use _.partial application. My point isn’t to say “Don’t use partial and partial right” Rather to say know both and know when to make use of each form. I hope you’ll look to use both styles.
  49. Short arrow functions are good. If they are more than two lines prefer named function expressions
  50. If you have a good size process, it helps clarity to start with a promise, even if it’s not a blocking operation