We still get all the ticks, all the way down to 0 (even though we don’t print it). Fixing
this problem is a little involved because we have already created all the timeouts (of
course, we could just “cheat” and immediately fail if a superstitious timer is created
for 13 seconds or longer, but that would miss the point of the exercise). To solve this
problem, once we discover we can’t continue, we’ll have to clear all of the pending
timeouts:
const
EventEmitter
=
require
(
'events'
).
EventEmitter
;
class
Countdown
extends
EventEmitter
{
constructor
(
seconds
,
superstitious
) {
super
();
this
.
seconds
=
seconds
;
this
.
superstitious
=
!!
superstitious
;
}
go
() {
const
countdown
=
this
;
const
timeoutIds
=
[];
return
new
Promise
(
function
(
resolve
,
reject
) {
for
(
let
i
=
countdown
.
seconds
;
i
>=
0
;
i
--
) {
timeoutIds
.
push
(
setTimeout
(
function
() {
if
(
countdown
.
superstitious
&&
i
===
13
) {
// clear all pending timeouts
timeoutIds
.
forEach
(
clearTimeout
);
return
reject
(
new
Error
(
"DEFINITELY NOT COUNTING THAT"
));
}
countdown
.
emit
(
'tick'
,
i
);
if
(
i
===
0
)
resolve
();
}, (
countdown
.
seconds
-
i
)
*
1000
));
}
});
}
}
Promise Chaining
One of the advantages of promises is that they can be chained; that is, when one
promise is fulfilled, you can have it immediately invoke another function that returns
a promise…and so on. Let’s create a function called
launch
that we can chain to a
countdown:
function
launch
() {
return
new
Promise
(
function
(
resolve
,
reject
) {
console
.
log
(
"Lift off!"
);
setTimeout
(
function
() {
resolve
(
"In orbit!"
);
},
2
*
1000
);
// a very fast rocket indeed
});
}
It’s easy to chain this function to a countdown:
210 | Chapter 14: Asynchronous Programming