‫In this video, we will promisify
‫the read file and write file functions.
‫Which means that we will make them so
‫that they return promises
‫instead of us passing a callback functions into them.
‫So if you want, it's basically a read file function
‫that returns a promise
‫and that only receives a file name, no callback.
‫So let's do exactly that.
‫So, we're gonna create a read file pro function.
‫So pro for promise because again
‫it returns a promise.
‫And then all we do is to pass in the file name
‫and as we were saying, return a promise.
‫So, return new promise.
‫So we use the promise constructor here
‫which was introduced into the language with ES6.
‫So before ES6 like ES5, ES4
‫and all the previous versions,
‫there was no support for promises in JavaScript.
‫But they changed that in ES6
‫and made the language a lot better in that regard.
‫So regarding asynchronous JavaScript.
‫Now this promise constructor here
‫takes in a so called executor function,
‫which will get called immediately when promise is created.
‫And this function will take in two arguments
‫so resolve and reject.
‫So resolve and reject,
‫but for now don't worry for them,
‫we're gonna be talking about them in a minute.
‫For now let's just focus on this executor function itself
‫because this is where we actually do
‫all this asynchronous work.
‫In this case the read file work.
‫So this is where we're gonna call fs.readfile
‫with the file name that was passed in
‫and then the usual callback function, okay.
‫So the error and data,
‫so just like before.
‫So keep in mind that we're not actually
‫changing the read file function
‫we're simply creating a new function
‫which behind the scenes of course still runs
‫the built in read file function
‫but then returns a promise
‫so that we can use the promise
‫instead of the callback function.
‫Okay.
‫So we have that read file function here
‫which will do its work
‫and when it's ready will come back with the data.
‫And now this is where the resolve
‫and the reject functions come into play.
‫Because both these arguments that are available
‫in the executor function they are both functions.
‫Now calling the resolve function
‫will basically mark the promise as successful
‫so as fulfilled,
‫and return the successful value from the promise.
‫So let's actually do that.
‫So we call resolve with data.
‫So whatever variable that we pass into the resolve function
‫is what will be later available
‫as the argument in the then method, all right?
‫So this data here will be the value
‫that this promise returns to us, okay.
‫That probably sounds a bit confusing, right?
‫So again, whatever we pass into this function here,
‫into the resolve function,
‫is the result of the promise
‫that will be available in the then handler.
‫Now on the other hand,
‫we can also mark the promise as rejected
‫in case there was an error, okay.
‫And we do that by calling,
‫as you can probably guess,
‫the reject function.
‫So, if there was an error
‫and this is similar to what we did before.
‫So if there was an error here,
‫then call the reject function.
‫And whatever we pass into this one
‫will be the error that is later available
‫in the catch method.
‫So, in this one here.
‫Okay?
‫So let's just pass a string in here,
‫I could not find that file,
‫some emoji here maybe to make it pop a bit more
‫in our console.logs, all right?
‫And, okay.
‫That is actually already it.
‫So, let's review this here again.
‫So we created a new file,
‫in there we will pass a file name.
‫So this argument.
‫And all we do here is to return this promise.
‫This promise takes in one executor function,
‫so this one here,
‫which is where we do our asynchronous work.
‫In that case here of course that is our
‫fs.readfile.
‫Then if we get our data in a successful way
‫we call the resolve function
‫with the resolve value.
‫And if there is an error
‫we call the reject function, okay?
‫And so let's now actually use this in practice.
‫Read file pro,
‫we pass in our file name.
‫So that's this one of course
‫and that's it.
‫So this will now return a promise.
‫And so just like before
‫we can then use our then method on that.
‫Okay and so this data argument here
‫will be exactly what we returned from the promise
‫in case it was successful.
‫So, with this resolve.
‫So right now our dog file here
‫contains labrador
‫and so this data here will be labrador.
‫And so that is then later available
‫in our then handler here.
‫But of course it doesn't need to have the same name,
‫I could also call it like result or something
‫it doesn't matter, all right?
‫Okay, so let's now take all of this
‫and actually put it here.
‫Okay.
‫Get rid of all of this, save it
‫and that will run it.
‫Now we get that error down here
‫so data's not defined.
‫That's because I changed it here to a result.
‫So let's actually go back and change it to data
‫because here we have data
‫and here we have data
‫and so this way I don't have to go ahead
‫and change all of these variable names.
‫Give it another save
‫and here we go.
‫So it worked, you see?
‫We actually got the breed,
‫which is still labrador
‫and this time from our promise, okay.
‫So, this really worked.
‫So our read file pro function
‫now returns a promise
‫and that data here is then available on our then handler.
‫Great, so it's already working
‫and we can make it a lot better
‫and we're gonna do that
‫but for now I also want to promisify
‫this write file function here.
‫So basically, do the same as we did
‫with the read file function.
‫Now, if you're already know a bit about no js,
‫maybe you're thinking that there is actually a function node
‫that will automatically promisify functions for us.
‫But of course I wanted to show you here
‫how promises actually work
‫and how we build them
‫and so that's why I'm doing all of this here, okay.
‫So I really want you to learn about promises,
‫not just how we consume them
‫but also how to build them.
‫And so that's why I'm doing it this way.
‫So, write file and as a promise.
‫And this one actually doesn't only need the file name
‫but also the data that should be written to that file.
‫But then the logic in here is quite similar.
‫So again, we return a new promise,
‫in there we have our executor function
‫which takes resolve and reject as the argument.
‫And these are kind of standard names
‫So resolve and reject,
‫you could call them whatever you really wanted
‫but this is kind of the standard, okay.
‫So fs,
‫write file,
‫we pass in the file,
‫the data and then the callback function.
‫And now something very similar to before,
‫so if there was an error,
‫then call the reject function
‫and pass in some message there.
‫Could not write the file,
‫again with this emoji here to make it stand out a bit more
‫and in case everything worked fine,
‫well then just resolve.
‫Now we don't have any data actually to pass in here right?
‫So we're just gonna pass in some random string
‫something just like saying success, okay.
‫So a promise doesn't always
‫have to return a meaningful value.
‫In this case all we're really trying to do here
‫is to write a file
‫which doesn't really return a meaningful value.
‫So we're now ready to use this promisified function
‫but before we do that,
‫let's actually implement the chaining
‫that I was talking to you about before.
‫So right now,
‫we still in fact have callbacks inside of callbacks
‫inside of callbacks, right?
‫So we have this then,
‫which has this callback.
‫And then in there there is another then handler
‫which has yet another callback in it.
‫So that doesn't really change anything, does it?
‫Instead we want to chain these then handlers here.
‫And the secret to doing that
‫is to make each handler return a new promise.
‫So how are we gonna do that?
‫Well, remember that this function here returns a promise.
‫And so all we have to do is to return
‫that promise from this first then handler.
‫Let me show that to you.
‫So we say return superagent.get
‫and then the string and that is now a promise, okay.
‫And then we actually close this callback function here
‫and chain this then method right onto it.
‫Give it a save, now we have some error here
‫and that is on line 40.
‫Let's get rid of this here
‫and okay.
‫It changed the formatting here for us again
‫that was prettier
‫and then we actually already have it working down here.
‫So why does this work again?
‫Well, of course this function
‫that we created in the beginning returns a promise.
‫So on that we can use the then method.
‫We then make this callback function that's in it
‫again return a promise.
‫And like that we can then chain
‫the next then handler on that.
‫So this result variable here
‫will then be the resolved value of this promise
‫that returned from the previous handler, okay?
‫Makes sense?
‫Now to take it one step further
‫we will go ahead
‫and use our write file pro function here now as well.
‫And since we want to keep chaining the then methods
‫we will again return that actually.
‫So return, write file pro
‫pass in the file name, which is this one,
‫the data...
‫And that's actually it.
‫Okay, so we don't need any of this here anymore,
‫let's just comment it up for now.
‫Get rid of this space here
‫and then on there we can chain the next then handler.
‫So then, and remember that in here
‫we didn't really have any meaningful resolved value.
‫So, we don't want any argument
‫to this callback function here
‫all we want to do is to log this string, right?
‫So now we can actually really get rid of this
‫and okay.
‫So, down here we see now
‫that it's actually already working.
‫And again the trick for being able
‫to chain all of these then methods here
‫is to return a promise before calling each of them.
‫So this one here obviously returns a promise here
‫so then we can chain the then method on it.
‫Then this piece of code here
‫will return a promise
‫and so we can use then on it.
‫Then this piece of code will return a promise
‫and so we can use then on it again, okay?
‫So that is the secret to it.
‫Give it a save again
‫and so down here we see that the breed is still labrador.
‫We see that this here is the link,
‫let's go here and confirm
‫that this is here indeed the same as this.
‫And so it did successfully write the string to the text file
‫using our promisified write file function, okay.
‫And then in the end we have this error handler.
‫And the beauty here is that for all of these chains
‫then handlers in the end,
‫we simply need one single catch handler.
‫So one function handling the errors
‫coming from either one of the three promises, okay.
‫Let's actually only log the error to the console
‫and let's try to, for example,
‫change this file here.
‫Actually not the file,
‫but I'm gonna change the file name here,
‫save it and now we see I could not find that file.
‫So where does that come from?
‫It comes right up here
‫from calling the reject function, okay?
‫So we have an error here because we couldn't find the file
‫and so we called the reject function.
‫And that reject function will then mark this promise here
‫so remember this is a promise.
‫It will mark it as rejected.
‫And therefore, the catch function is called.
‫And so then we log that error to the console.
‫And the result of that is what you can see down here.
‫Okay, let's put it back
‫now it works.
‫Now let's go into the file,
‫create a dog that doesn't exist
‫and now, oh, here we have this big weird error
‫and that's because we're simply logging the entire error
‫and not the error message as we were doing before
‫but doesn't matter.
‫Now give it a save here now,
‫put it back
‫and all right.
‫So now it's all working
‫and we got rid of that triangular shape
‫that we had in our code
‫and now have a so called flat structure of chain promises.
‫So again this is way easier to manage
‫and I hope you can start to appreciate that
‫and it's also more logical to think
‫and to reason about the code like this.
‫Now, in the next lecture
‫we will actually take it one step further even
‫and make this even more readable
‫and easier to use.
‫So stay tuned for that.