‫Let's now write some code
‫in order to get a better understanding
‫of what happens in the event loop.
‫So just like before, to get started
‫with the coding part of this section,
‫go ahead and grab the starter files
‫for this section, copy them somewhere,
‫and then open up the project in your code editor.
‫So I have it here on the desktop,
‫and in my VSCode, and all we have here to start
‫is this test-file.txt, and so I'm gonna create
‫a new file here, and I'm gonna call it the event-loop.js.
‫Alright, now it is actually extremely difficult
‫to simulate the event loop properly,
‫because we can't really put many callbacks
‫in all the callback queues that we
‫talked about before all at the same time, right.
‫That situation happens when for example
‫a lot of requests are coming into your app,
‫but here locally, that's just very hard to replicate.
‫But anyway, we will still do some very interesting
‫experiments using some of the stuff
‫that we learned in the last video.
‫And what we're gonna do is to write a bunch
‫of lines of code, and then try to figure out
‫in which order they should be executed
‫in the event loop, and analyze if the results
‫that we get actually make sense.
‫So let's start by writing a setTimeout,
‫so basically in order to set a timer,
‫and I'm using an arrow function here,
‫and the only thing that I'm gonna do
‫is to log to console some string,
‫so console.log, timer one finished,
‫and I want this to expire right after zero seconds.
‫Okay, give it a save, and then you see
‫that it actually corrected this string here,
‫so it changed this quotes, and added the semicolon,
‫and that's because of the Prettier
‫extension that we installed before.
‫Now I'm not gonna configure it here,
‫because for this small example,
‫that's not really necessary, okay.
‫So that is setting a timer, then let's also use
‫setImmediate, so remember that from the last video.
‫Okay, now I'm not gonna explain a lot here,
‫for now let's write this code,
‫and then analyze what happens, okay.
‫So setImmediate, and just like the other timer,
‫it receives a callback function.
‫And all we're gonna do is to write
‫immediate one finished, and this one doesn't have
‫any time, because it's not necessary
‫because as the name says, it is immediate.
‫Then another thing that we want to do
‫is to read this file here, and then pass
‫a callback function, okay, so the first thing
‫is that we have to require the correct module, so FS,
‫and now fs.readFile, and we want text-file.txt,
‫and then something to happen.
‫And just like before, let's just say here,
‫in this case I/O finished, alright.
‫So I/O because this callback here
‫is actually related to a I/O task,
‫which actually gets it's own phase in the event loop, right.
‫And then finally, let's just add a console.log here,
‫saying well, hello from the top level code.
‫Okay, and so top level code, because it's actually
‫the only one that is not inside of any callback.
‫So in this very small example that we have for now,
‫let's try to figure out what should happen first.
‫Well, remember that the first step
‫when we load a module is that it's top level code
‫gets executed, so right away we should see
‫this console.log here, right, only then later
‫we should see the other logs coming from
‫these other callbacks, because these callbacks
‫will actually run in the event loop.
‫So let's try to see if that's actually the case,
‫and then analyze it a bit better even.
‫So opening up the console here, and again,
‫I'm doing that by using terminal,
‫or actually in the view, so this terminal here, alright.
‫So note, event-loop.js, or actually
‫before we do so, I need to fix this typo here,
‫so it's test file, not text file.
‫Okay, but now we're ready to run this command,
‫and the results are in, so the first log
‫that we have here is hello from the top level code,
‫and that was expected, right, because
‫this is a code that gets executed immediately.
‫Then after that, we have these three outputs,
‫but they are actually in no particular order,
‫and that's because this code here,
‫so this code, is actually not in an I/O cycle,
‫so it's not running inside of the event loop,
‫because it's not running inside of any callback function.
‫Okay, so in your computer, you might actually see
‫this log here before this one,
‫and then this one here is only the last one
‫because this kind of big file here
‫takes some time to read, and so it's
‫probably always gonna be the last one.
‫So again, at this point, the order of these three here
‫doesn't have anything to do with the event loop,
‫because they're actually not running
‫inside the event loop just yet.
‫For that, we will have to move them,
‫or at least move these two here, inside a callback function.
‫And so, for that we're gonna use this one here actually.
‫So let me put it here, and say timer two and timer two here,
‫or immediate two, and I'm also gonna add another timer here,
‫so timer three, and this one is gonna run
‫for three seconds, so that is 3000 milliseconds.
‫So let's now try the result of this one.
‫But before we do that, let's actually think
‫why right after all the code before had run,
‫the program then exited and went back to the prompt here.
‫So remember how Node.js decides if it should continue
‫running the event loop, well it does so
‫by asking if there is still any time running
‫in the background, and if so, it will not finish,
‫and if there is still a pending timer,
‫well then it's not gonna exit the program.
‫But if there's not, which was the case
‫in the first example here, then it immediately
‫exits the program, okay, but now we actually
‫have one timer here, so this one will run
‫for three seconds, and so let's try
‫to figure out what happens here.
‫Okay, so you see that it's not exiting,
‫and only now, after timer three has finished,
‫it did then exit the application.
‫Okay, so let's actually just see that again,
‫so all these logs timers running, timer finished,
‫and so it exited the application.
‫Now about these results here, let's actually make
‫this here a bit easier to see,
‫and add just a small separator here.
‫Okay, clean this, okay.
‫So these four ones here are the outputs
‫that were not really running in the event loop,
‫but these three here were actually coming
‫out of the event loop, so let's now analyze these results.
‫Now, if you'll remember the diagram
‫from the previous lecture, you will probably have thought
‫that the timer, so timer two here,
‫should actually finish before the setImmediate,
‫because in the diagram, it actually appeared first
‫right at the top of the event loop.
‫So we have to set timeout here with zero,
‫which should kind of be the same as setImmediate, right.
‫So why does setImmediate actually
‫appear before the setTimeout?
‫Well, there's something that I didn't really explain
‫in the last video, because I didn't want to make it
‫even more confusing, and that is that the event loop
‫actually waits for stuff to happen in the poll phase.
‫So in that phase where I/O callbacks are handled.
‫So when this queue of callbacks is empty,
‫which is the case in our fictional example here,
‫so we have no I/O callbacks, all we have
‫is these timers, well then the event loop
‫will wait in this phase until there is an expired timer.
‫But, if we scheduled a callback using setImmediate,
‫then that callback will actually be executed
‫right away after the polling phase,
‫and even before expired timers, if there is one.
‫And in this case, the timer expires right away,
‫so after zero seconds, but again, the event loop
‫actually waits, so it pauses in the polling phase.
‫And so that setImmediate callback
‫is actually executed first, so that is the whole reason
‫why we have this immediate here after we have the timers.
‫Okay, and I know this sounds very confusing,
‫and I completely agree, but really
‫that's just the way Node.js works.
‫And now let's make this even a little bit more confusing,
‫and add the process.nextTick that
‫we talked about also in the last lecture.
‫So we say process.nextTick, and then just like before,
‫we simply pass it a callback function.
‫And again, I just wanna log to console,
‫and I'm gonna say process.nextTick.
‫So what do you think will happen in this case?
‫Go ahead and make a guess, and once you're ready
‫you can then run this, so let's do that.
‫Save it here first, run it, and so here we go.
‫So the results are again in, and now the first callback
‫that was executed was actually this function here.
‫So that's why we have process.nextTick
‫right in the first one.
‫So why was this callback function of process.nextTick
‫the first one of all of them to be executed?
‫Well, remember that nextTick is part
‫of the microtasks queue, which get executed
‫after each phase, so not just after one entire tick.
‫And so what happened here is that this callback function
‫actually ran before the phase where this callback function
‫here ran, and the phase before that, okay.
‫Now nextTick is actually really a misleading name,
‫because a tick is actually an entire loop,
‫but nextTick actually happens before the next loop phase,
‫and not the entire tick, so that's what I was saying before.
‫Then on the other side, setImmediate would make you think
‫that it's callback would be executed immediately,
‫but it actually doesn't, right, so setImmediate
‫actually gets executed once per tick,
‫while nextTick gets executed immediately.
‫And so their two names should actually be switched.
‫They should be the other way around,
‫and this can cause a lot of confusion,
‫so it's best to just always stick to one of them,
‫and that's usually setImmediate and not process.nextTick.
‫Now anyway, as I mentioned in a last video,
‫these mechanisms are actually more for pretty advanced
‫use cases, which is why we will
‫probably not use them in our project.
‫But if you want to learn more about them,
‫you can always read the official Node documentation.
‫Okay, so with this we have simulated
‫some aspects of the event loop,
‫but to finish, I want to just quickly
‫introduce something about thread pool as well,
‫and for that we're gonna do a more complex operation
‫that will actually be offloaded to the thread pool,
‫and take a look at how long these operations take to run,
‫and how we can change the thread pool
‫size that we talked about before.
‫So we're gonna use some cryptography here
‫to basically encrypt a password.
‫So that's a new package we hadn't used before,
‫and it's called Crypto, but I mentioned earlier
‫that actually, all the functions from this package,
‫they will be offloaded automatically by the event loop
‫to the thread pool, and so that's
‫what we're gonna test out now.
‫And let's use this now, so crypto.pb,
‫so we're gonna use an encryption function called pbkdf2,
‫so kind of a weird name, and now we pass in
‫the secret string, which let's just say password,
‫then we need a string to solve the passwords,
‫and the implementations here don't really matter,
‫so for now I'm not gonna go into any detail
‫of how this works, we're gonna do that later, okay,
‫so here we just need the key length,
‫so this number here is just for the number
‫of iterations, then this is the key length,
‫and then finally the algorithm,
‫which is gonna be used to encrypt the password.
‫So these numbers will simply increase
‫the time it takes for the encryption.
‫Okay and then finally, it also takes a callback function,
‫and all I'm gonna do here is to do another console.log,
‫and just say password encrypted.
‫Now, for the purpose of this demonstration,
‫I actually want to show you how much time
‫each of these operations take, so what we're gonna do
‫is to basically define a variable in the beginning,
‫set it to date.now, so that is the current date
‫in milliseconds, and then here, all we have to do
‫is to log not only the string, but also date.now,
‫which will be the date at this point in milliseconds,
‫minus the start, and so that will then give us
‫the amount of milliseconds that have passed
‫in order to do this calculation.
‫Okay, so let's try it out, give it a save,
‫and run it again, and so here you see
‫that it took 1855 milliseconds,
‫so almost two seconds to encrypt this password.
‫Okay, but now let's actually duplicate
‫this code, or actually I want four instances
‫of this to show you something.
‫So if we run this now, it should probably take
‫approximately the same amount of time,
‫and yeah it does, so it was 1.8 seconds,
‫now it's 2.2 seconds, which is quite similar.
‫Okay, and remember that I told you in one of
‫the earlier lectures, that by default
‫the size of the thread pool is four,
‫so there are four threads doing the work
‫at the same time, and so that's why
‫these four password encryptions
‫take approximately the same time
‫and happen basically all at the same time.
‫But we can actually change that thread pool size.
‫So, let me show you how we do that,
‫and we do that by saying process.env,
‫and that's an environmental variable,
‫and again we're gonna talk more about that later,
‫and UV, which stands for LibUV,
‫threadpool size, so if we set this to one,
‫we will only have one thread in our thread pool.
‫So let's try that again, and so let's see what happens now.
‫So you see that they all take much longer to calculate.
‫Basically, they are calculated one after the other.
‫So this one the first, then this one here takes
‫double the time, and again that's because
‫this one can only start as soon as
‫the first one is completed, and the same
‫with the third and the fourth one.
‫Now let's say we change it to two,
‫then we should see the first two ones
‫with the same time, and exactly,
‫the second two also with a similar time.
‫So that makes sense, right.
‫Just for the sake of completion here,
‫now the same with three, so these three
‫have a similar time, and then the last one.
‫Alright, so this is how the thread pool works basically,
‫so I decided to not only focus on the event loop,
‫but also to give you an overview, a very quick one,
‫of the thread pool and how we can change
‫the thread pool size, okay, keep in mind
‫that this code here is actually still
‫asynchronous, because we passed in a callback function.
‫Okay, and we could actually use the synchronous version,
‫but that would then block the event loop.
‫Wanna see that?
‫So let me very quickly show that to you as well,
‫so that one was not really planned,
‫but let's do it anyway, 'cause it's
‫very interesting to see that I think.
‫Okay, so that will work like this.
‫We use again the sync version of the same function,
‫which a note, is many times available.
‫Remember we have the same for the read file,
‫so we have read file, which accepts a callback,
‫and we have read file sync, which is the synchronous version
‫which doesn't accept any callback, so just like this.
‫So this one will then encrypt the password,
‫block the code execution, and then move on to the next line,
‫which will then log this here to the console.
‫So let's now duplicate this here.
‫That was too much, get rid of this one here,
‫and so now these four password encryptions
‫will no longer run in the event loop.
‫And so they will no longer be offloaded to the thread pool.
‫Okay, and so now even if we have the thread pool size
‫of four, let's see what happens.
‫So you see, they happen completely in a synchronous way.
‫So one after the other, and what is even worse,
‫is that all of these timers here,
‫even nextTick and the immediate one,
‫only appeared after the password encryptions happened.
‫So this really was blocking the entire execution,
‫even if this timer here, for example this one here,
‫was finished after zero seconds,
‫and this one after three seconds,
‫but they all have to wait seven seconds
‫until all of these password encryptions here
‫were finally ready, again because they were not running
‫inside the event loop, but these were.
‫And so they were basically working in the background
‫and could only be picked up by the event loop
‫when they were ready, right after these four
‫password encryptions, so this one was
‫another great example of seeing the
‫code blocking and event loop all in action.
‫Okay, so that was enough for one lecture,
‫I hope that you found it interesting,
‫and I'll see you right in the next one.