PROMISESTHE UNSUNG HEROES OF ASYNC IN
JAVASCRIPT
DEAN RADCLIFFE • OK GROW! •
@DEANIUSDEV
A SPORTING BET
"I BET YOU $20 THE REDS
WON'T BEAT THE CUBS
THIS SEASON..."
TWO PROMISES
➢ Begin Season
then Cubs Lose
then Season Ends
↩ I Pay You
➢ Begin Season
then Season Ends
↩ You Pay Me
TWO PROMISES
➢ Begin Season
then Cubs Lose
// ^ What if we made the bet after a loss ?
then Season Ends
↩ I Pay You
➢ Begin Season
then Season Ends
↩ You Pay Me
PROMISES: EVENTS, AT ANY TIME
A Promise represents a point in time which is:
▸ ASAP, if something has already happened
▸ ASAP the moment it happens
PROMISES: VALUES, AT ANY TIME
A Promise provides access to a value whether:
▸ It is already known
▸ It is being computed in this turn of the Event Loop
▸ It may be un-knowable (maybe use a TimeOut)
PROMISES: ONE OR MORE CONDITIONS & ACTIONS
A Promise can represent an entire chain of events,
with branching possibilities.
var firstStep = new Promise()
var allSteps = firstStep
.then(isReady => isReady || makeReady)
.then(lastStep)
Promise.await(allSteps)
OUR BET - MAKE IT SO
➢ let ourBet = BeginSeason()
.then(Promise.race(CubsLoseToReds(), SeasonEnds()))
.then(cubsLose => cubsLose ? iPayYou : youPayMe)
//.then(iPayYou, youPayMe)
▸ CubsLoseToReds and SeasonEnds return Promises
▸ CubsLose should return truthy (such as the score),
▸ SeasonEnds should return falsy, or throw or reject
UNSUNG HEROES OF ASYNC
▸ Standard, explicit contract of behavior
▸ A promise can resolve or reject
▸ Its state may change 1x from pending to fulfilled
▸ p.then(youPayMe, iPayYou)
▸ Or: p.then((value)=>{})
.catch((err)=>{})
BACK ON THE CHAIN GANG
Each step in a .then chain:
RETURNS A CUMULATIVE PROMISE FOR ALL BEFORE
➢ let chain = promise1
.then(promise2)
.then(action1)
BACK ON THE CHAIN GANG
Each step in a .then chain may:
RETURN A VALUE / RETURN A PROMISE FOR A NEW VALUE
➢ BeginSeasonLossless
.then(CubsLoseToReds) // <-- a Promise
.then(iPayYou)
BACK ON THE CHAIN GANG
Each step in a .then chain may:
RAISE AN EXCEPTION / RETURN REJECTED PROMISE
➢ BeginSeasonLossless
.then(Promise.race(CubsLoseToReds,TimeOutAtSeasonEnd))
.then(iPayYou)
.catch(youPayMe)
EXCEPTIONS
▸ An uncaught exception in a .then is OK!
▸ A catch at the end can handle errors for the whole chain
COMIC RELIEF
CAT PICTURE
QUESTION: HOW DO THESE EVENTS BEHAVE ?
If you add an event listener after an event has happened,
does it make a sound ?
document.addEventListener("DOMContentLoaded")
// vs.
$(document).ready
// vs.
$(document).on("ready")
QUESTION: HOW DO THESE EVENTS BEHAVE ?
If you add an event listener after an event has happened,
does it make a sound ?
document.addEventListener("DOMContentLoaded")
// vs.
$(document).ready // <<-- only this one - like a Promise
// vs.
$(document).on("ready")
PROVIDED ITS LOADED, 1
➢ DomContentLoadedPromise.then(function () {
console.log('Im ready')
});
↩ Promise {[[PromiseStatus]]: "resolved"}
-----
Im ready
PROVIDED ITS LOADED, 2
➢ DomContentLoadedPromise.then(function () {
console.log('Im ready')
});
↩ Promise {[[PromiseStatus]]: "pending"}
-----
PROVIDED ITS LOADED, 2..
➢ DomContentLoadedPromise.then(function () {
console.log('Im ready')
});
↩ Promise {[[PromiseStatus]]: "pending"}
-----
...
PROVIDED ITS LOADED, 3
➢ DomContentLoadedPromise.then(function () {
console.log('Im ready')
});
↩ Promise {[[PromiseStatus]]: "pending"}
-----
...
_____
Im ready
WHAT'S WRONG WITH CALLBACKS ?
Implicit, not formalized standard of behavior:
1. Function that takes 2 arguments
▸ first argument is an error
▸ second argument is the result
▸ Never pass both
▸ error should be instanceof Error
WHAT'S WRONG WITH CALLBACKS ?
Implicit, not formalized standard of behavior (cont.)
1. Must never execute on the same tick of the event loop
2. Must be passed as last argument to function
3. Return value is ignored
4. Must not throw / must pass resulting errors
5. Must never be called more than once
WHAT'S WRONG WITH CALLBACKS ?
▸ Burdensome to check & propogate errors correctly
function doAsyncStuff (cb) {
try {
doStuff1(function(err, value) {
if (err) return cb(err);
try {
doStuff2(value, function(err, value2) {
if (err) return cb(err);
cb(null, value2);
});
} catch (e) {
cb(e);
}
})
} catch (e) {
cb(e);
}
}
WHAT'S RIGHT WITH PROMISES ?
BEAUTIFUL TO CHECK ERRORS, EXCEPTION OR ASYNC!
// Promises FTW !!
function doAsyncStuff () {
return doStuff1()
.then(doStuff2)
.catch(function(err){ /*...*/})
}
THE EVENT LOOP
(AKA TASK
QUEUE)
THE EVENT LOOP (AKA TASK QUEUE)
THE 2 WAYS OF
CODING JS
PROMISES AND REACTIVITY
Keep an upperCase var in sync with
a variable called lowerCase
let lowerCase = new ReactiveVar
let upperCase = new ReactiveVar
PROMISES AND REACTIVITY
Keep an upperCase var in sync with
a variable called lowerCase
let lowerCase = new ReactiveVar
let upperCase = new ReactiveVar
Tracker.autorun(() => {
let x = lowerCase.get()
upperCase.set(x.toUpperCase())
})
PROMISES AND REACTIVITY
Keep an upperCase var in sync with
a variable called lowerCase
lowerCase.set(x).then((x) => {
upperCase.set(x.toUpperCase())
})
PATTERN
RETURNING A PROMISE FROM
A METEOR METHOD
RETURNING A PROMISE FROM A METEOR METHOD
Return a Promise from a Method
Return an Eventual Value from a Method
RETURNING A PROMISE FROM A METEOR METHOD
Return a Promise from a Method
Return an Eventual Value from a Method
Eventually return a value from a Method
RETURNING A PROMISE FROM A METHOD, 1
Meteor.methods({
futureTime() {
return Promise.await(
);
}
})
RETURNING A PROMISE FROM A METHOD, 2
Meteor.methods({
futureTime() {
return Promise.await(new Promise((resolve) => {
//some callback code which should call 'resolve'
}));
}
})
RETURNING A PROMISE FROM A METHOD, 3
Meteor.methods({
futureTime() {
return Promise.await(new Promise((resolve) => {
setTimeout(() => {
console.log("its the future now")
resolve(new Date())
}, 5000)
}));
}
})
RETURNING A PROMISE FROM A METHOD, 4
Meteor.methods({
futureTime() {
let actions = new Promise((resolve) =>
setTimeout(()=> resolve(new Date), 5000))
.then(logAndReturn)
.catch(logAndReturn);
return Promise.await(actions);
}
})
ASYNC SHEEP
CALLING A METHOD
Meteor.promise("futureTime")
.then(log)
CALLING A METHOD, NOW AND LATER
➢ Promise.resolve(new Date)
.then(log)
.then(() => Meteor.promise("futureTime"))
.then(log)
---
Fri Sep 18 2015 22:11:26 GMT-0500 (CDT)
↩ Promise {[[PromiseStatus]]: "pending"}
---
Fri Sep 18 2015 22:11:31 GMT-0500 (CDT)
CALLING A METHOD, FUNNILY
Promise.resolve(new Date)
.then(log)
.then(() => "futureTime")
.then(Meteor.promise)
.then(log)
---
Fri Sep 18 2015 22:11:46 GMT-0500 (CDT)
↩ Promise {[[PromiseStatus]]: "pending",
---
Fri Sep 18 2015 22:11:51 GMT-0500 (CDT)
var ComicReliefCatPicture; // TODO fill in
PROMISES AND REACTIVITY
okgrow:promise
A promise's resolution can invalidate a
computation ?
Awwwwwww yeah !
DEFINE A HELPER AROUND A PROMISE
<template name="example1Demo">
<input id="arg1" value="foo"/>
<input id="arg2" value="bar"/>
<textarea>
{{meteorPromise "addWithSleep" "arg1" "arg2"}}
</textarea>
</template>
RETURN A PROMISE FROM A HELPER
// {{meteorPromise "addWithSleep" "arg1" "arg2"}}
Template.example1Demo.helpers({
meteorPromise: function (methodName, part1, part2) {
var template = Template.instance(),
value1 = template[part1].get(),
value2 = template[part2].get();
// want to - but cant do this !
return Meteor.callPromise(methodName, value1, value2);
}
});
RETURN A PROMISE FROM A HELPER
// {{meteorPromise "addWithSleep" "arg1" "arg2"}}
Template.example1Demo.helpers({
meteorPromise: ReactivePromise(theHelperFunction, {pending: "loading..."})
});
var theHelperFunction = function (methodName, part1, part2) {
var template = Template.instance(),
value1 = template[part1].get(),
value2 = template[part2].get();
return Meteor.callPromise(methodName, value1, value2);
}
TMTOWTDI
CALLBACKS, PROMISES, FIBERS,
REACTIVITY, AND ES6 GENERATORS ARE
ALL WAYS TO BE ASYNC!
(YOU CAN ALWAYS CONVERT)
QUESTIONS ??
PROMISES Я AWESOME
PROMISES Я AWESOME
AND SO ARE YOU!
DEAN RADCLIFFE, OK GROW!
@DEANIUSDEV

Promises - The Unsung Heroes ofJavaScript

  • 1.
    PROMISESTHE UNSUNG HEROESOF ASYNC IN JAVASCRIPT DEAN RADCLIFFE • OK GROW! • @DEANIUSDEV
  • 2.
    A SPORTING BET "IBET YOU $20 THE REDS WON'T BEAT THE CUBS THIS SEASON..."
  • 3.
    TWO PROMISES ➢ BeginSeason then Cubs Lose then Season Ends ↩ I Pay You ➢ Begin Season then Season Ends ↩ You Pay Me
  • 4.
    TWO PROMISES ➢ BeginSeason then Cubs Lose // ^ What if we made the bet after a loss ? then Season Ends ↩ I Pay You ➢ Begin Season then Season Ends ↩ You Pay Me
  • 5.
    PROMISES: EVENTS, ATANY TIME A Promise represents a point in time which is: ▸ ASAP, if something has already happened ▸ ASAP the moment it happens
  • 6.
    PROMISES: VALUES, ATANY TIME A Promise provides access to a value whether: ▸ It is already known ▸ It is being computed in this turn of the Event Loop ▸ It may be un-knowable (maybe use a TimeOut)
  • 7.
    PROMISES: ONE ORMORE CONDITIONS & ACTIONS A Promise can represent an entire chain of events, with branching possibilities. var firstStep = new Promise() var allSteps = firstStep .then(isReady => isReady || makeReady) .then(lastStep) Promise.await(allSteps)
  • 8.
    OUR BET -MAKE IT SO ➢ let ourBet = BeginSeason() .then(Promise.race(CubsLoseToReds(), SeasonEnds())) .then(cubsLose => cubsLose ? iPayYou : youPayMe) //.then(iPayYou, youPayMe) ▸ CubsLoseToReds and SeasonEnds return Promises ▸ CubsLose should return truthy (such as the score), ▸ SeasonEnds should return falsy, or throw or reject
  • 9.
    UNSUNG HEROES OFASYNC ▸ Standard, explicit contract of behavior ▸ A promise can resolve or reject ▸ Its state may change 1x from pending to fulfilled ▸ p.then(youPayMe, iPayYou) ▸ Or: p.then((value)=>{}) .catch((err)=>{})
  • 10.
    BACK ON THECHAIN GANG Each step in a .then chain: RETURNS A CUMULATIVE PROMISE FOR ALL BEFORE ➢ let chain = promise1 .then(promise2) .then(action1)
  • 11.
    BACK ON THECHAIN GANG Each step in a .then chain may: RETURN A VALUE / RETURN A PROMISE FOR A NEW VALUE ➢ BeginSeasonLossless .then(CubsLoseToReds) // <-- a Promise .then(iPayYou)
  • 12.
    BACK ON THECHAIN GANG Each step in a .then chain may: RAISE AN EXCEPTION / RETURN REJECTED PROMISE ➢ BeginSeasonLossless .then(Promise.race(CubsLoseToReds,TimeOutAtSeasonEnd)) .then(iPayYou) .catch(youPayMe)
  • 13.
    EXCEPTIONS ▸ An uncaughtexception in a .then is OK! ▸ A catch at the end can handle errors for the whole chain
  • 14.
  • 15.
    QUESTION: HOW DOTHESE EVENTS BEHAVE ? If you add an event listener after an event has happened, does it make a sound ? document.addEventListener("DOMContentLoaded") // vs. $(document).ready // vs. $(document).on("ready")
  • 16.
    QUESTION: HOW DOTHESE EVENTS BEHAVE ? If you add an event listener after an event has happened, does it make a sound ? document.addEventListener("DOMContentLoaded") // vs. $(document).ready // <<-- only this one - like a Promise // vs. $(document).on("ready")
  • 17.
    PROVIDED ITS LOADED,1 ➢ DomContentLoadedPromise.then(function () { console.log('Im ready') }); ↩ Promise {[[PromiseStatus]]: "resolved"} ----- Im ready
  • 18.
    PROVIDED ITS LOADED,2 ➢ DomContentLoadedPromise.then(function () { console.log('Im ready') }); ↩ Promise {[[PromiseStatus]]: "pending"} -----
  • 19.
    PROVIDED ITS LOADED,2.. ➢ DomContentLoadedPromise.then(function () { console.log('Im ready') }); ↩ Promise {[[PromiseStatus]]: "pending"} ----- ...
  • 20.
    PROVIDED ITS LOADED,3 ➢ DomContentLoadedPromise.then(function () { console.log('Im ready') }); ↩ Promise {[[PromiseStatus]]: "pending"} ----- ... _____ Im ready
  • 21.
    WHAT'S WRONG WITHCALLBACKS ? Implicit, not formalized standard of behavior: 1. Function that takes 2 arguments ▸ first argument is an error ▸ second argument is the result ▸ Never pass both ▸ error should be instanceof Error
  • 22.
    WHAT'S WRONG WITHCALLBACKS ? Implicit, not formalized standard of behavior (cont.) 1. Must never execute on the same tick of the event loop 2. Must be passed as last argument to function 3. Return value is ignored 4. Must not throw / must pass resulting errors 5. Must never be called more than once
  • 23.
    WHAT'S WRONG WITHCALLBACKS ? ▸ Burdensome to check & propogate errors correctly function doAsyncStuff (cb) { try { doStuff1(function(err, value) { if (err) return cb(err); try { doStuff2(value, function(err, value2) { if (err) return cb(err); cb(null, value2); }); } catch (e) { cb(e); } }) } catch (e) { cb(e); } }
  • 24.
    WHAT'S RIGHT WITHPROMISES ? BEAUTIFUL TO CHECK ERRORS, EXCEPTION OR ASYNC! // Promises FTW !! function doAsyncStuff () { return doStuff1() .then(doStuff2) .catch(function(err){ /*...*/}) }
  • 25.
  • 26.
    THE EVENT LOOP(AKA TASK QUEUE)
  • 27.
    THE 2 WAYSOF CODING JS
  • 28.
    PROMISES AND REACTIVITY Keepan upperCase var in sync with a variable called lowerCase let lowerCase = new ReactiveVar let upperCase = new ReactiveVar
  • 29.
    PROMISES AND REACTIVITY Keepan upperCase var in sync with a variable called lowerCase let lowerCase = new ReactiveVar let upperCase = new ReactiveVar Tracker.autorun(() => { let x = lowerCase.get() upperCase.set(x.toUpperCase()) })
  • 30.
    PROMISES AND REACTIVITY Keepan upperCase var in sync with a variable called lowerCase lowerCase.set(x).then((x) => { upperCase.set(x.toUpperCase()) })
  • 31.
    PATTERN RETURNING A PROMISEFROM A METEOR METHOD
  • 32.
    RETURNING A PROMISEFROM A METEOR METHOD Return a Promise from a Method Return an Eventual Value from a Method
  • 33.
    RETURNING A PROMISEFROM A METEOR METHOD Return a Promise from a Method Return an Eventual Value from a Method Eventually return a value from a Method
  • 34.
    RETURNING A PROMISEFROM A METHOD, 1 Meteor.methods({ futureTime() { return Promise.await( ); } })
  • 35.
    RETURNING A PROMISEFROM A METHOD, 2 Meteor.methods({ futureTime() { return Promise.await(new Promise((resolve) => { //some callback code which should call 'resolve' })); } })
  • 36.
    RETURNING A PROMISEFROM A METHOD, 3 Meteor.methods({ futureTime() { return Promise.await(new Promise((resolve) => { setTimeout(() => { console.log("its the future now") resolve(new Date()) }, 5000) })); } })
  • 37.
    RETURNING A PROMISEFROM A METHOD, 4 Meteor.methods({ futureTime() { let actions = new Promise((resolve) => setTimeout(()=> resolve(new Date), 5000)) .then(logAndReturn) .catch(logAndReturn); return Promise.await(actions); } })
  • 38.
  • 39.
  • 40.
    CALLING A METHOD,NOW AND LATER ➢ Promise.resolve(new Date) .then(log) .then(() => Meteor.promise("futureTime")) .then(log) --- Fri Sep 18 2015 22:11:26 GMT-0500 (CDT) ↩ Promise {[[PromiseStatus]]: "pending"} --- Fri Sep 18 2015 22:11:31 GMT-0500 (CDT)
  • 41.
    CALLING A METHOD,FUNNILY Promise.resolve(new Date) .then(log) .then(() => "futureTime") .then(Meteor.promise) .then(log) --- Fri Sep 18 2015 22:11:46 GMT-0500 (CDT) ↩ Promise {[[PromiseStatus]]: "pending", --- Fri Sep 18 2015 22:11:51 GMT-0500 (CDT)
  • 42.
  • 43.
    PROMISES AND REACTIVITY okgrow:promise Apromise's resolution can invalidate a computation ? Awwwwwww yeah !
  • 44.
    DEFINE A HELPERAROUND A PROMISE <template name="example1Demo"> <input id="arg1" value="foo"/> <input id="arg2" value="bar"/> <textarea> {{meteorPromise "addWithSleep" "arg1" "arg2"}} </textarea> </template>
  • 45.
    RETURN A PROMISEFROM A HELPER // {{meteorPromise "addWithSleep" "arg1" "arg2"}} Template.example1Demo.helpers({ meteorPromise: function (methodName, part1, part2) { var template = Template.instance(), value1 = template[part1].get(), value2 = template[part2].get(); // want to - but cant do this ! return Meteor.callPromise(methodName, value1, value2); } });
  • 46.
    RETURN A PROMISEFROM A HELPER // {{meteorPromise "addWithSleep" "arg1" "arg2"}} Template.example1Demo.helpers({ meteorPromise: ReactivePromise(theHelperFunction, {pending: "loading..."}) }); var theHelperFunction = function (methodName, part1, part2) { var template = Template.instance(), value1 = template[part1].get(), value2 = template[part2].get(); return Meteor.callPromise(methodName, value1, value2); }
  • 47.
    TMTOWTDI CALLBACKS, PROMISES, FIBERS, REACTIVITY,AND ES6 GENERATORS ARE ALL WAYS TO BE ASYNC! (YOU CAN ALWAYS CONVERT)
  • 48.
  • 49.
  • 50.
  • 51.
    DEAN RADCLIFFE, OKGROW! @DEANIUSDEV