-
Notifications
You must be signed in to change notification settings - Fork 25
Step 2: DRYer Code
Daniel Levy edited this page Aug 16, 2017
·
7 revisions
- Promisify Callback-based libs/dependencies w/
Bluebird.promisify
,Bluebird.promisifyAll
, ordenodify
. - Replace all occurrences of
callback(...)
with either areturn Promise.reject(err)
for errors, or anything else for success (Promises and values are handled the same). - Ensure every function uses
return
at least once. - Remember you can start a Promise-chain with literals or variables using
Promise.resolve(user)
. - If you don't have a 'starting' value/parameter you can always
.resolve()
w/o params. Like so:() => Promise.resolve().then(lookupGps)
.
This may look like a lot of change for a single step, however all these steps are required before your code improves.
The first few times you go through this process it'll seem fraught with peril. With a bit of practice, it actually becomes a very speedy process. I used to take 3+ hours converting a 500-line file. Now the same size task takes about 15-30 minutes. See Common Issues section below.
- Use destructuring for function params. This makes it easier to understand exactly what a function needs, which should make it's purpose clear (assuming a reasonable name).
const auth = ({user, pass}) => {}
- Conversely, finding the
return
s in the function should let you quickly reason about the code-execution-path.
The previous 2 steps have a way of forcing you to write focused single-purpose functions.
I understand if Promises are maddening at first.
I used to run into 2 issues seemingly constantly: no visibility into errors and forgetting to return
.
It turns out they are potentially related issues.
- These issues: 'silent exit with or w/o error' or 'empty return value' or hanging
.then()
have 2-3 general causes:- 95% of the time: Failed to
return
from function. - 4% of the time it's a complicated hierarchy - say +3 Promise chains deep. This will resemble
callback hell
. Don't do this - either break apart the 3 Promise chains, or flatten it out into 1 promise declaration. A good Promise nesting rule-of-thumb: only nest a new Promise 'chain' when inside a collection method callback (i.e. Bluebird's .map, or .mapSeries). - 1% it is a bug in calling
Promise.reject(new Error)
requires valid Error instance. Avoidthrow
ing errors - while bluebird is pretty awesome at handling this, it's too easy tothrow
from a different async context. The result can be a meaningless stack traces. To get some hint as to where it went haywire enable LongStackTraces, or promisify the async code you're calling & plug it into your Promise chain.
- 95% of the time: Failed to
Make sure to read the install guide for Bluebird - look for long stack trace support.
- Steps
- Bonus Material