- [Instructor] Promises give us a nice way to organize
what happens by chaining together .then handlers.
We use this technique to compose promise chains
that can execute sequentially.
But what if you don't want to compose functions in a chain?
What happens when you just want to write code?
All we really need to do is wait for the result
of one promise to complete before running some more code.
Do we always have to encapsulate code bits
in tiny functions?
The answer is no.
JavaScript provides us a way to work with promises
using code that appears synchronous,
but is in fact asynchronous.
The solution is async functions.
Inside of an async function,
you can await for a promise to complete.
Let's look at how we can modify the current
sequentially executed promise chain
using async and await.
So the doStuffSequentially function,
to get started I'm just gonna go ahead
and delete these last lines of code,
the last .thens that we added
to the doStuffSequentially function.
And what I'm gonna go ahead and do
is I need to make this into an async function.
So you make an async function,
simply by typing async right in front
of the function declaration.
And I'm gonna get rid of this Promise.resolve call,
and we will operate this function
right between the brackets.
So what an async function allows us to do
is write code that appears synchronous.
So we can write code line-by-line,
and we can tell certain lines to wait for a result
before executing any further.
So I'll just go ahead and add a console.log starting.
Seems to be the first thing that we have.
And now, inside of an async function,
I can use the await key word, with a promise.
So this await will await a delay of one second.
So before we execute any code found on line 13 and beyond,
we will wait for the delay promise to be resolved.
So I'll go ahead and console.log waiting.
And then we can await another delay.
And I'll go ahead and await a writeFile.
So this works with any promise.
And we've created a writeFile promise
using the utilities promisify function.
So we will write some sample text to this file.
And when we're done writing the file,
we'll go ahead and beep.
We can just invoke that as a function.
So file.txt created.
And then after we create that file,
we'll go ahead and await another delay.
We'll wait for three seconds.
And then we will await the unlink promise, file.txt.
So we're doing the exact same thing
that we did with the thenables,
but notice this code looks a little bit more synchronous.
It's a little cleaner to edit.
There we go.
So now I can get rid of this entire .then chain,
because the doStuffSequentially function
will still operate sequentially.
It still uses promises, but as opposed to wiring up
every handler and additional then statements,
we can actually write the code line-by-line
and just call certain lines to wait.
Let's go ahead and run this
and see what happens in our terminal.
And here we see roughly the same results.
Now since we didn't see this in the last lesson,
I'm gonna go ahead and open up my files.
So here's my project folder.
I got there by typing command backslash.
Let's go ahead and run it again,
just so we can see that file getting created.
And being removed.
So there's file.txt.
One of the benefits of writing code this way
is we can handle errors with tryCatch blocks.
That will allow us to specify what errors
we want to handle exactly.
Like, for instance, I could put a try,
and catch block around this writeFile and beep.
And I can handle the error that way.
So now if anything goes wrong with writing the file,
we can go ahead and add that error,
or we can actually create a new error,
if we wanted to.
We could surround the entire function
in a tryCatch block if we wanted to.
That would be available to us, as well.
And then finally, if we wanted
to keep the doStuffSequentially function working
the exact way it did in the past,
it would need to return a promise.
So all we need to do is return Promise.resolve.
And now in this case, the return is not direct style.
So because we're in a asynchronous function,
all of these lines that have awaits
are gonna wait before processing any further,
so we will wait for the file to be unlinked
before we return a resolved promise.
And just returning that promise resolve,
allows me to then dot chain extra thenables on here,
or use the doStuffSequentially within its own
async await function.
Now, I do want to delete this
and actually show one more quick example.
So there is one more thing that I want to show you
about asynchronous functions before we move on,
and that is that we can also obtain data from them.
So let's say that we wanted to use
a read directory promise.
We can go ahead and create one up here, readdir.
And the readdir will read our directory,
because we're gonna promisify the fs.readdir method.
So if I were to execute this promise, readdir,
and say .then, I would actually get the files
as an argument passed to the thenable,
because the read directory promise is gonna read directory
and then give me a result.
So we can also obtain the data
that would be resolved in a promise
in an async await function, too.
I'll give you an example.
We'll go ahead an create an async function,
async function start.
And when we go ahead and start this program,
we will get the files by saying var files
equal the result of await.
So we're still using the promise.
Go ahead and read the files in the current directory.
And then I can go ahead and log those results.
So because the readdir is a promise,
we are still waiting for it to be resolved
before moving to line 14.
Any data that the readdir promise would return,
we can actually set using an equal sign,
because line 13 is going to await for readdir to resolve
and return its results.
So let's go ahead and give this a shot.
I can clear out my current terminal,
type node dot one more time.
Oops, I better call start.
So we put it in an asynchronous function called start,
and then forgot to invoke it.
So let me go ahead and add that
and try this one more time,
over in the terminal, node dot.
And we can see that we have two files
in the current directory.
So asynchronous functions give us a really nice way
to organize our code in a more manageable fashion.