- [Instructor] In the first lesson,
we introduced sequential execution with callbacks
and we saw how nesting too many callbacks
can create an anti-pattern called callback hell
or the pyramid of doom.
Let's take a deeper look at this anti-pattern.
So inside of our example file,
inside of chapter one, chapter one lesson five,
the index.js has this huge pyramid of doom.
So what's going on here is we're using a couple resources.
We're using the file system.
We're gonna write and delete the file.
And then on line two, we are actually setting up a function
that will cause the computer to beep.
So if we write the standard output, this \xO7 code,
that will actually cause the MacOS to beep,
so we will hear a beep when we run this.
Now this doStuffSequentially is one function,
but this function has a lotta callbacks.
So on line five we see that the function is starting,
that's the first step.
And then on line six, we're gonna set a timeout.
We can't see how long that timeout is all the way down
'til line 30.
That looks crazy.
And then when the timeout is done,
we're gonna write waiting
and then we're gonna set another timeout
and wait some more.
And then we're gonna write a file.
And when that file has been written successfully,
we'll go ahead and beep.
We'll log that the file has been created.
So you can see that we have a lot of sequential steps
all nested within callbacks
and it makes it really hard to work with.
Let's go ahead and go to the terminal
and take a look at what the output looks like.
So I'm gonna call node., we see that we're starting,
waiting, everything is processing sequentially.
We heard the beep, we heard another beep.
So we created a .txt file, we removed a .txt file
and then we called sequential execution complete.
So all of these things are happening in order, yes,
but this code would be a nightmare to maintain or edit.
So let's take a look at how Promises
can help us resolve this anti-pattern.
So the first thing we're gonna do is we are also
going to include our promisify utility.
And now that we have our promisify utility,
what I wanna do is make sure that our writeFile,
is fs.writeFile.
So we wanna turn writeFile into a promise.
We also wanna turn unlink,
this will actually delete a file, into a promise.
So we have unlink and writeFile as promises.
We have our beep function.
We can keep that as a function.
What we're gonna do is create a delay promise.
So this is our delay promise from earlier
to give the seconds.
That will return a new promise.
We're not gonna handle the rejects on this promise,
'cause we're just gonna call a setTimeout
and resolve.
So we'll resolve that
after a certain number of seconds has passed.
So that's our same delay promise from earlier.
So now we have promises.
We have writeFile, unlink, and delay.
So let's take a look at how we can execute things
sequentially as promises.
So I'm just gonna modify this, doStuffSequentially,
and turn it into a promise.
So it'll still be a function.
And instead of returning a new promise,
what I'm gonna do is invoke promise.resolve.
So that will create a new promise object,
but it will automatically resolve it.
Now the point of doing this,
is I can then chain up the sequential steps
using then methods.
So the very first step was to actually
log to the console that we're starting.
So there's our first.
And then in the next then method,
what I'm gonna do here is return a promise.
So at this point we can delay for one second.
So when I return a promise inside of a then method,
that means that the then method will wait for this delay
before invoking the next .then method.
So in this case we can go ahead and
we'll just return the message waiting
and then we'll go ahead and console.log that message.
So remember in our thenables if a function returns something
it can be used in the next thenable.
And the reason we're using console.log
as opposed to taking in the message
and console logging
the message, is because just adding the console.log function
will do the same thing,
because message is the first argument
that would be sent to this function.
If you add it like this, be careful not to invoke it.
We want to wait to invoke console.log
until the waiting message has been displayed.
So then that takes us through here.
So it looks like then we have another delay.
So I will go ahead and call delay.
And this time our delay is for two seconds.
So after this delay what I can do is write the file.
So since we have a promise,
we can simply return that promise write.File.
And we'll write file.txt
and then go ahead and say it's a Sample File.
So we will wait for node.js to write the file
before invoking the next then.
So in this case, we'll go ahead and just add the beep.
So then we will add a beep
and then after we beep
we can go ahead and return the message,
file.txt created.
And then after we do that
we can console.log that message.
Then we'll go ahead and do another delay.
So we'll delay for three seconds.
After we delay for three seconds,
we will then delete the file.
So we can call an unlink, file.txt.
And after we have deleted the file,
we will go ahead and beep again.
So we're following the same process
that's in this pyramid of doom.
And then after we beep,
we will go ahead and just say file.txt removed
and that .then(console.log)
and if anything goes wrong, we wanna handle it.
So we're gonna add one catch method
to catch anything that goes wrong.
And we will go ahead and take that error.
So something else we can do is throw the error.
So I could say error, console.error
and then throw the error in there.
And again, just like our earlier console.log,
all the catch function needs is a function as the argument.
So this will actually do the exact same thing.
If I just pass it the console.error,
it will then throw that first error argument
up to the console.
So there is another way to handle things sequentially.
And this time using Promises,
we can see that our code is much cleaner,
much easier to organize.
Everything's happening in order.
Let's go out to our terminal and give this a shot, node dot.
So we can see that we're starting, waiting,
things are happening sequentially,
just like they were in the pyramid of doom,
although it is much easier to manage this.