Promises are to Async like JQuery was to the DOM. Learn a bit about how Meteor does async, then learn how to use Promises to tame callbacks, interoperate with non-Meteor libraries, and accomplish other feats of wizardry.
2. A SPORTING BET
"I BET YOU $20 THE REDS
WON'T BEAT THE CUBS
THIS SEASON..."
3. TWO PROMISES
➢ Begin Season
then Cubs Lose
then Season Ends
↩ I Pay You
➢ Begin Season
then Season Ends
↩ You Pay Me
4. 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
5. 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
6. 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)
7. 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)
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 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)=>{})
10. 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)
11. 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)
12. 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)
13. EXCEPTIONS
▸ An uncaught exception in a .then is OK!
▸ A catch at the end can handle errors for the whole chain
15. 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")
16. 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")
17. PROVIDED ITS LOADED, 1
➢ DomContentLoadedPromise.then(function () {
console.log('Im ready')
});
↩ Promise {[[PromiseStatus]]: "resolved"}
-----
Im ready
21. 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
22. 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
28. PROMISES AND REACTIVITY
Keep an upperCase var in sync with
a variable called lowerCase
let lowerCase = new ReactiveVar
let upperCase = new ReactiveVar
29. 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())
})
30. PROMISES AND REACTIVITY
Keep an upperCase var in sync with
a variable called lowerCase
lowerCase.set(x).then((x) => {
upperCase.set(x.toUpperCase())
})
32. RETURNING A PROMISE FROM A METEOR METHOD
Return a Promise from a Method
Return an Eventual Value from a Method
33. 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
34. RETURNING A PROMISE FROM A METHOD, 1
Meteor.methods({
futureTime() {
return Promise.await(
);
}
})
35. RETURNING A PROMISE FROM A METHOD, 2
Meteor.methods({
futureTime() {
return Promise.await(new Promise((resolve) => {
//some callback code which should call 'resolve'
}));
}
})
36. 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)
}));
}
})
37. 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);
}
})
44. 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>
45. 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);
}
});
46. 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);
}