I strongly suggest you return a promise from a method even at the early stages of prototyping if there is a chance the data will later be generated asynchronously. This adds only a tiny complexity overhead, but will make painless the switch in the future.
Example
Let us represent user information as an object. The user has several bits of information, all set in the constructor.
1 | function User(username, profile) { |
Notice that profile
property might be a candidate to be fetched separately from the
server. Thus to prepare for this change, instead of having a string primitive property,
I wrap it in a promise, even if the value exists already
1 | var q = require('q'); |
I do not like the syntax foo.profile.then
- to me it looks a little weird.
Instead I prefer promise-returning methods
1 | var q = require('q'); |
A transition to fetching the profile from the server now is trivial
1 | var q = require('q'); |
Promises are functors
The above example shows how I prepare for asyncronous data flow. The primitive values wrapped like this
have another name: functors. Instead of using the primitive value I wrap it in an object that only has
to provide a method to run a function on the primitive. In the case of promises, this method is .then
.
It takes a single callback function, passing the primitive value. After the function returns, a new
promise is returned that wraps around the value returned from the callback function.
1 | function double(x) { return x + x; } |
With functors, we do not use the underlying primitive value itself, as you saw from the example. Even pure printing now requires passing a callback function
1 | function double(x) { return x + x; } |
One final detail: every returned value is wrapped in promise, thus the above example
finishes with a promise wrapping an undefined
value.
1 | q('foo').then(function (result) { |
In general, using functors instead of primitives makes your software more flexible. You can find more examples of functors in these 3 blog posts
- Functors and Applicatives - including lots of cat pictures to illustrate wrapping primitive values.
- Functors, Applicatives, And Monads In Pictures - starts with functors, and then explains through pictures other two concepts around wrapped values: applicatives and monads.
- Promises are the monad of asynchronous programming - wraps promise creation method
q(value)
and separates mapping operation into external function, pushing promises from just functors to monads.