error handling. In this example, all we’re doing is logging the errors, but if we tried
throwing an exception, we’d be in for another rude surprise. Consider the following
simpler example:
const
fs
=
require
(
'fs'
);
function
readSketchyFile
() {
try
{
fs
.
readFile
(
'does_not_exist.txt'
,
function
(
err
,
data
) {
if
(
err
)
throw
err
;
});
}
catch
(
err
) {
console
.
log
(
'warning: minor issue occurred, program continuing'
);
}
}
readSketchyFile
();
Glancing over this, it seems reasonable enough, and hooray for us for being defensive
programmers and using exception handling. Except it won’t work. Go ahead and try
it: the program will crash, even though we took some care to make sure this semi-
expected error didn’t cause problems. That’s because
try...catch
blocks only work
within the same function. The
try...catch
block is in
readSketchyFile
, but the
error is thrown inside the anonymous function that
fs.readFile
invokes as a call‐
back.
Additionally, there’s nothing to prevent your callback from accidentally getting called
twice—or never getting called at all. If you’re relying on it getting called once and
exactly once, the language itself offers no protection against that expectation being
violated.
These are not insurmountable problems, but with the prevalence of asynchronous
code, it makes writing bug-free, maintainable code very difficult, which is where
promises come in.
Promises
Promises attempt to address some of the shortcomings of callbacks. Using promises
—while sometimes a hassle—generally results in safer, easier-to-maintain code.
Promises don’t eliminate callbacks; as a matter of fact, you still have to use callbacks
with promises. What promises do is ensure that callbacks are always handled in the
same predictable manner, eliminating some of the nasty surprises and hard-to-find
bugs you can get with callbacks alone.
The basic idea of a promise is simple: when you call a promise-based asynchronous
function, it returns a
Promise
instance. Only two things can happen to that promise:
it can be fulfilled (success) or rejected (failure). You are guaranteed that only one of
those things will happen (it won’t be fulfilled and then later rejected), and the result
Promises | 205