Now certain operations, like reading a file,
or talking to a database,
are typically solved with asynchronous code,
and very often, therefore,
with callback functions like this.
Now sometimes you have multiple asynchronous tasks
that depend on each other.
For example,
we could be reading some file content there.
And then in there we want to start another async task
that sends the data to a database.
So then we would have an async task
that's started from inside this callback function,
once this async task finished.
Now, whilst we don't know yet how to talk to a database,
we'll dive into that in the next course sections,
I can already tell you
that since that would be another async task,
we would have a never callback function in the end,
that would be executed once that second async task,
talking to a database, is done.
And the more async tasks you have to depend on each other,
the more callback functions inside of callback functions
you might have at the end.
And that's something
which is sometimes referred to as callback. Hell,
because it can make your code a bit hard to read,
if you start adding more code inside of a callback function,
that then internally again,
relies on a callback functio,
because you have more and more indentation to the right,
and more and more callback functions
that are nested into each other.
That's why we have an alternative way
for dealing with asynchronous code,
which is supported by a lot of built in packages,
and third-party packages.
Specifically, I'm talking about a concept called promises.
Now what's a promise?
Well, in real life,
a promise is if I tell you
that I will give you back the money you borrowed me,
I give you the promise of giving you back the money
you gave me, in the future.
It's basically an asynchronous task, right?
You give me money today.
I returned that money to you in the future.
So the operation starts instantly.
You give me the money.
But the result of the operation,
that I return you to money,
occurs in the future.
And I promise to do that.
In JavaScript, we have the same concept.
With a callback, it's pretty much all the same,
but it's a callback function which we're using here.
It's one way of dealing with async code,
which has potential downsides,
as mentioned a couple of seconds ago.
Now we can also require this file system package,
by requiring fs slash promises.
Now this might look weird,
but that's another built-in package.
And that simply gives us promise versions
off file system methods.
I'll comment out this callback version for that.
And instead again, use fs, and again use read file.
Now read file still wants to know where the file is.
So we still pass that path to read file,
but it now does not want a callback anymore.
Instead, read file now returns a so-called promise,
which is simply a kind of object
that's baked into browser side and Node JS JavaScript.
It's a standardized object
with certain properties and methods,
and specifically it has a then method, which we can execute.
So the result of calling read file is a promise,
because I'm getting fs from that fs promises package.
And since the result of read file is a promise,
I can call then on that promise,
because promises are objects
that always have a then method,
simply because the promise blueprint,
which is baked into JavaScript,
defines such a then method in that blueprint.
The then method then, again,
takes a function, an anonymous function,
or a predefined function,
which might get some value,
depending on how that promise is configured.
In case of that read false promise,
we'll get the file data as a value.
So this function, which we passed to then,
is again, executed automatically for us,
by JavaScript and read file,
once reading the file is done.
And the line after read file, by the way,
is also still executed immediately
after this process was started.
That doesn't change.
Now, we just don't pass our callback function to read file,
but instead to then, which will call on read file.
And in there we can now, again, console log,
as I did it before.
So console log the file data, and file parsing done.
Now, if I saved this and I execute async JS,
you'll see it works as before.
We get the same output, and we get it in the same order.
Hi there is output first,
because this line of code
is executed immediately after read file was started.
And then once the file parsing is done,
that content here, or that code executes,
and therefore we get this output,
but what's now the advantage of using promises?
In the end it's almost the same,
just to be half this extra then method.
Well,
the advantage is that this allows you to write code
in a more structured way.
If you, for example,
would have another asynchronous operation
that you want to trigger from inside this callback function,
you can return another async operation.
That's just some dummy code here, of course.
And then if you return,
then you could add another then block here
with another anonymous function
that will execute once that async operation finished.
And then you can also write this code
in a more structured way like this.
And that will lead to a highly readable promise chain,
as it's called,
where you can combine multiple asynchronous operations
into a clearly structured line of operations like that.
It, again,
doesn't matter too much to our trivial example here,
but promises are a very modern and popular way
of handling async operations,
simply because they allow you to write code
in a more structured way.
And using promises often is an alternative
to using callback functions,
but it will always depend on the package you're using,
whether they offer you both callbacks and promises,
or adjust callbacks, or just promises.
Here, I want to show you both,
and here you see how you can read a file with a callback,
or by using a promise.