Skip to content

Instantly share code, notes, and snippets.

@hoodwink73
Last active August 22, 2017 04:02
Show Gist options
  • Save hoodwink73/1475d907f83cf4f9b5281c7e537155ca to your computer and use it in GitHub Desktop.
Save hoodwink73/1475d907f83cf4f9b5281c7e537155ca to your computer and use it in GitHub Desktop.
Promises are the power horse of async paradigm in JS
// try-catch blocks cannot handle async errors
function foo() {
setTimeout( function(){
baz.bar();
}, 100 );
}
try {
foo();
// later throws global error from `baz.bar()`
}
catch (err) {
// never gets here
}
// to get around these, we started using
// error-first callback pattern
function foo(cb) {
setTimeout( function(){
try {
var result = baz.bar()
cb(null, result)
} catch (e) {
cb(e)
}
}, 100 );
}
// this works, but what if `baz.bar` has an async block inside which
// throws an error after an arbitary amount of time, it will suffer from
// the same shortcoming – try-catch blocks cannot catch async errors
// so, error-first callbacks are not composable, unless we keep on passing
// callbacks upwards to catch errors
var p = Promise.resolve(21);
// `then` is the magic sauce which transforms a promise
// what computation results in the transformation, you ask?
// the logic inside the fulfillment callback
var p2 = p.then(function fulfillmentCallback (v) {
console.log(v); // 21
return v * 2;
})
// `p2` is a new promise which gets resolved
// with value `v * 2` since it was returned by
// the `fulfillmentCallback`
p2.then(function (v) {
console.log(v); // 42
})
// But `then`s are chainable, we could do without
// saving the intermediate promise in `p2`
p
.then(v => v * 2)
.then(v => log(v)) // 42
// Above, we are creating sequence of steps following
// a presumably async action
// each call to `then` are just a step in this sequence
// But what if we wanted each step to have the affordance
// to be performed asynchronously
// we can return a Promise from the `fulfillmentCallback` passed
// to `then`
p
.then(v =>
new Promise(
(resolve, reject) =>
resolve(v * 2)
)
)
// this step will be passed the value
// with the above Promise resolves
// note intuition might suggest that
// the `fulfillmentCallback` in this step
// would get passed the Promise as an argument
// but thats not what it would get
.then(v => log(v)) // 42
// now a promise can resolve right away
// or later, so any step now in the sequence
// can be delayed until the resolution of the previous step
p
.then(v =>
new Promise(
(resolve, reject) =>
setTimeout(() => resolve(v * 2), 1000)
)
)
.then(v => log(v)) // 42
// above we see examples of how messages are passed
// through each step in the aync sequence. But it is not
// necessary that each needs to pass a message, a step's resolution
// can solely serve as a signal for the next step in the sequence to begin
var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
delay(100)
.then(
// note that there is no message being passed from
// the previous step
() =>
return delay(200)
)
.then(() => console.log('I will happen after 300ms'))
// when a promise fails, but there is no rejection handler,
// the promise chain makes an assumption
p = new Promise(function (resolve, reject) {
reject(42);
})
// here `p` is rejected, but because it is not
// handled, `p2` will also get rejected with the
// same error, this is how an error propagates a
// promise chain
p2 = p.then(function () {
// never gets here
})
if (!Promise.map) {
Promise.map = function (vals, cb) {
return Promise.all(vals.map(function () {
return new Promise(function (resolve) {
cb(val, resolve)
})
}))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment