 All right. Hi everyone. I think we are live. Yeah, I think so. I don't know. If somebody on the chat, please join the chat, okay guys? So if you're watching, you should be joining the chat and you know, because this is an interactive workshop, so get ready and get out of your keyboard. So please, if somebody on the chat gives us a ping and says, hey, all of these is actually okay and working, that would be pretty nice. Anyway, yay, yay. I don't know. If somebody on the chat, please join the chat, okay guys? So if you're watching, you should be joining the chat. Okay, so I can mute ourselves. Okay, so there is a little bit of a delay here, but hopefully we'll get through this. So, hi, I'm Matteo and this is James. I don't know James, hey. How's it going? All right. So we're going to be talking about the use of promises and JavaScript in a node. And a couple of important things to know about this is this workshop that we're going through, it's actually, all of the material was prepped for an eight hour workshop that we do, spread over two days. And we're condensing a lot of material down into just an hour and a half and we're definitely not going to be able to touch on everything, you know, but we want to go through the most significant bits. So quick reminder for you to follow us on Twitter. So at Jasnel, at Matteo Collina, follow us. We'll tweet about things on Node.js JavaScript. We ramble about promises most of the time, whatever. So let's get started. So, hey, again, we both work for a company called Nierform, you probably know us. If not, check us out. We do professional services. For the, you know, in the JavaScript community and beyond. And I would say let's get started because we have not so much time and a lot of things to talk about. By the way, as we are a professional services company, if you like the workshop and if you want more content, something this, some consulting and so on, please reach us out. The first question that we have for all of you, it's how well do you know promises? And this is one of the nicest thing that we can ask to everybody. Now, there's a little bit of delay between this and that and then, and when you'll see this, so we will probably just skip a little bit of the answer for this specific question, but we'll assume you know that the promise is very, very well in this workshop. And hopefully we are going to shatter your knowledge of promises if we can. And also the Node.js event loop. So let's get started. One thing that's very important to understand is everything that we're gonna show you, everything that we're gonna talk about is stuff that we have experienced actually out in the field with real code out in production. None of this is just kind of made up, right? These are all issues that we have seen and helped fix in real code. Yay, so now it's very easy to do promises incorrectly. Promises are fantastic, by the way. They simply, especially think away, simplify a lot of things. However, it's actually very, very easy to mess up. And from my experience is understanding our JavaScript and Node.js schedule code together with promises and so on and so forth is actually key to understand Node.js performance and writing production Node.js code that runs really, really well. So in this workshop, again, this is a shortened version of this workshop, unfortunately. So we're not going to cover all of this. It's just one hour and a half if we're going to go through all those three points, which is our promises work, how to use promises correctly and the cost of getting promises wrong. Unfortunately, we have no time to cover the last one of the items. But there is some few exercises you will see them as part three on the GitHub repo that I'm going to pass in the chat as well so that you can actually get to... So you can actually follow along. So near form just a second and then from this workshop, and then I'm going to copy this and I am going to pass it. Well, I'm going to say what I was doing now. One of the other important differences here is when we normally do this kind of workshop, this longer version of it, we would typically break everyone up into groups to go off and work on an exercise for a while. We can't do that here in this format. So you pretty much be going through the exercises on your own, but feel free to use the chat to share ideas and as we're going through things to kind of discuss each of the exercises. So, okay, so let's get started. You will need to get the latest Node.js versions which the latest Node.js thing which is 12.18 or higher and then whatever code editors that you need. Then please clone the workshop and run npm install. Now, this is the time where we'll typically ask our crowd to run a quick puzzle and do the thing themselves. However, typically this is an exercise that will take you maybe half an hour to get somewhere into it. We probably don't have that much time. So I will ask James, James will actually walk you through the, walk you through the exercise. James, so I'm stopping sharing now and James, you can take over. All right, let me go ahead and take over. After I do this, I'm gonna, I am gonna step away to get some headphones because I do apologize if there is an echo in the audio steps of hair. Let me switch over to this just real quick. In this puzzle, the trick is this code, print the message to the console, but you are in your challenge is to figure out what the message says without running the code. And I really challenge you to stop and take a look at it. Try to figure it out, reason through what this code is doing, the order in which things are executing. Because one of the things that we've found is that the absolute key to node performance, it's a Java script, is to really be able to reason about and understand the order in which your code is executing what bits of code come before others. And to really understand, one key question is what parts of this code are blocking the event loop? And the obvious answer is all of it is anytime JavaScript is running, the event loop is being blocked. Anytime you're using scheduling mechanisms, there's some complexity that you need to reason about. So take some time to go through this code and if you can figure out the message without running it, let me know and let both of us know. You can ping us on Twitter in the chat or whatever. And, but just ask you, don't give it away for other folks. By the way, folks, it doesn't, don't cheat and run it, okay? Don't cheat and run it. Oh, and once you figure it out in the puzzle.js, there's a second version here, puzzle.mjs, which runs it as an ES6 module. All we've done is renamed the file. The question for you is, is it going to print the same message? So I'll leave it with that in the tail. I'm gonna return control back to you and I'm gonna step away for just a second and get some headphones. Hooray! So we are back into the, we are, which file is also, they're asking which file is it? Okay. So if you go to github.com slash nearform slash promises workshop, the file that we were mentioning is on section order and first.js. Oh, no, sorry. It's section is section and puzzle and puzzle.js. So this file, it's this file here. So that's the question from the folks in the chat. Okay, so let's go and jump to, let's go and jump into, here you go, the next one, the next one. So now, one of the key questions that you are joining the broken promises workshop, right? So one of the key question you want to ask is how does a sync JavaScript work? Well, this is a nice question and you should all ask those questions and never take it from granted. If you're not familiar with those topics, please take some time to reason about this. Well, the reason how a sync work is by through the event loop. So whenever you're scheduling something that talks to the network or you do an HTTP request or you want to read the file or talk to a database or a lot of other things like that, you have, you're passing through the Node.js event loop. What does it mean? Well, it means that, you know, you will be called back when something is done or with promises, a promise will resolve. Now we are going to go through, I'm going to give you 15 minutes to solve to work on an exercise. And this is actually one of the nicest exercises. So I would give you 15 minutes to run this code and possibly figure out what some rules about the event loop. Now, the code is this file in here is section one order and first.js. Increase your font size there, Matteo. Oh yeah, here we go. Better? Much. So this particular bit of code, it's using a number of different mechanisms similar to the puzzle to schedule some functions. So the first thing we need to do in this 15 minutes is go through, again, without running it, build a hypothesis for what order. Well, also, you can also run it. This one, James, again, if they want to run it, you can run it because there is the second step. So if you go into this file, you can go to order, there is a readme, and then it tells you about first.js, which, you know, try to work out some hypothesis on the values of synchronous way that are run. Then you can run second and see the difference and trying to understand and adjust your hypothesis and then run the m.js one, which is the one using Async, the one for the new module system and Neckmaster modules, and see even there is even more difference there. And, you know, you should try to understand why that happens. And I know a few things in there, a few people in the audience are actually going to tell that there is a difference there, why that happens. But, you know, I guess that would be it. So I'm going to, with James and myself, I'll probably keep an eye on you folks for the next 10, 15 minutes or something and so on. So that would be pretty nice and so on. I don't know if you need to go. All right, so go ahead and start working through that example. If you have not cloned that repo yet, go ahead and grab a clone of it. Matteo posted the link. It's the NearForm Promises Workshop repository. Clone that you want to take a look at exercises, section one order to take a look at the code. You can also take a look at it on the, you know, on GitHub if you don't want to clone it and don't want to run that locally. The key thing with this exercise is to understand what is happening. You know, build a hypothesis as you're going through in terms of what order things are going to be executing and why and to really start to understand the differences in those, in timing. We're going to go through and start breaking down why this matters here in just a short while. And as always, any questions that you have drop them into the chat. I don't see anybody putting it, writing anything in the chat. So I hope they are following. So. Okay, if you're getting a reference error for QMicroTask not being defined, then you're going to want to do is check what version of Node that you're running. You want to make sure that you are on Node version 12.18 or higher. And if you're still getting QMicroTask issue, then you're going to, yeah, there's some other problem going on. As you've got, you know, if we can ask you just so we can judge progress. If you've gone through the example, all three examples, you know, maybe just go ahead and put a quick note in the chat. If you are getting stuck on anything, just throw a note in there as well. You can say your findings in the chat, yay. Yeah. So as you're going through this, if you're not already familiar, I mean, between the puzzle in this example, what becomes obvious is that there are many ways of scheduling code to run in Node, right? We have timers, we have next ticks, we have immediate, we have promises. The puzzle example makes use of worker threads. All of these things, you know, are, you know, kind of work together to schedule, to schedule this asynchronous activity. One of the things that is key is to understand how these relate to one another, how they interact with one another. And where in the process of, you know, this Node application that's running, you know, where are these things coming into play? I have a question in the chat here. What is the micro task thing? It's actually one of the key things that we're going to go through in just a couple of minutes for those that don't understand it. There is somebody that actually making some progress, which says that there is a difference between first and second. It depends on when set immediate schedules and which is, which he finds very confusing. Well, everybody finds that very confusing, not just you, every single person. And then it's, and for MJS, it says when the micro task is scheduled before next tick and vice versa. All of those things are very, very important bits that we will need to go through and explain in detail, essentially. So, you know, just for the sake of time, you know, we definitely need to make sure that we can keep going on this. So the one thing I will point out with the first and second examples there. Note that the first one, all of those things are being scheduled just as your main entry point. So, you know, when you Node first, right? That code that's executed and run. Node actually loads and executes that file as part of its own bootstrap. And the event loop is not started until after that code executes. It's a key thing that not a lot of people understand. You know, they think, you know, hey, it's running a node, it's always running in the event loop. That's not necessarily true. The code that's run right when you start node is always run before the event loop starts. In the second example though, you're running that scheduled code after the event loop starts in a callback that is called from within the event loop, right? And so the difference in timing, the difference in order of execution of those pieces relates specifically to when the event loop is actually started and whether that code is running within the event loop or not. I should also give you a clue why the MJS version is different as well. Mateo, do you wanna start walking folks through it? Okay, yeah, I can definitely start walking people through this, which will be pretty good and nice. So here we go. I am going to stop sharing this and I am going to execute it on my terminal. Okay, in the meantime, James, there is a question. So if you can answer the question. But so the use cases for these other commands besides promise. So it's important to understand things like timer set immediate next tick. Those all existed in nodes before promises ever existed. When they were introduced, particularly when next tick was introduced, there was no way of scheduling this kind of async activity using promises. They just wasn't there. So now that we do have promises, these things kind of coexist with each other and interact with each other. Set immediate is actually a form of, similar to timer. So set time out, set interval, set immediate kind of go together. It's a way of scheduling activity to run on the event loop at a particular time. We'll go through the differences in these later on, but it's important to understand that promises don't actually have anything to do with the event. James, can you read my screen well just so that you're there? It's okay, my one I increase your font size just a little bit. Better? Yeah. Okay. Yeah, better, right? Yep, better. Okay. Keep going. I'm ready. Okay, so you can go ahead and take it off. Yeah, we're gonna go into more detail about how these interrelate with each other. Very recent. So you, let's say that we start running our code and say run first.js, okay? So let's see, let's open up our first.js file and let's look at the code. So first thing we run, we run new promise and so we run this new, we call this new promise, right? As you can see from the code on the, from the output on the left, this is the very first sentence and that's being printed. So this means that this function that we pass to new promise is executed immediately. However, the second sentence is not then one, which means that it will resolve asynchronously. So promises are executed immediately and will resolve and we always resolves asynchronously. Where we'll talk about that in a second and in which order. The second bit that we are showing is a nothing function which essentially it's kind of the same as the previous part. We're doing the same thing of the previous lines of code but it's, we're actually using the new syntax for them async functions that have been introduced. So we call our async function and then we call async functions always returns a promise and then we call dot then and then we log then two. These also are scheduled afterwards, okay? Then we schedule a bunch of set immediate, set time out, next take, micro task, set time out, set time out, blah, blah, blah, blah, blah. So let's go through the output order. So the first thing that we see, we see that next takes as executed immediately, process dot next take here. The few, all of them at the same time. This is actually very interesting because we can draw an immediate rule. Next take is actually a very bad name for something. Next take does not mean next take, okay? It's actually the very, very bad name and with a lot of legacy and I deeply regret that they didn't change the name of this API deeply. The difference here is that, so the name of next take means at the end of the current JavaScript execution. So it means that at the end of the current JavaScript execution, that will function will be called. So essentially, it doesn't even touch the event loop. It executes before the event loop is finished. Yeah, this is a critical thing and we're gonna show this in just a minute of what exactly we mean here. But when it comes to next takes and micro tasks, so promises, those do not run on the event loop, okay? And those are independent of the event loop. But things like set immediate, set timeout, set interval, timers, those do run on the event loop. So understanding the differences in timing of those things has a critical impact on performance just in being able to reason about the execution flow of your JavaScript. Very, very key critical concepts and we're gonna walk through exactly what we mean by that in just a minute. Okay, so let's keep going. Then we have next take, then we have the values then. So first thing is executed is next take. Next take are super high priority things. After that queue of next take are executed, we run the micro task queue, which was added later in the game, of later in the evolution of JavaScript. Next take was added by Node.js at the very early beginning and the micro task queue and promises was added way later, way later. So then we have the two thens that we have added. Note that those, which is one is this and the other one is this guy, those two are like kind of siblings. So they are run at the same in the same micro task at the same level of the micro task queue. So note, as you see, all the next take queue is exhausted before touching the micro task queue. Notice here, it's important. One important thing to notice here too is that the two thens are run before the two micro tasks. So we have a promise scheduled the dot then and we have an async function that schedules a dot then. And then later on we have the queue micro tasks here. The reason that these thens come first, right, is because those promises are resolved, are being resolved synchronously, right? As soon as the code is being run, right? As soon as the new promise is being run, we resolve. So we're not resolving those asynchronous. We're not resolving those in the future. We're resolving them right now, which means that the then gets added to the micro task queue immediately. And it ends up getting added before the queue micro task is actually getting built. So now let's go to one of the important piece, which is the difference between set time out and set immediate. Now this set time out, we have talked about promises, right? Oh, note, queue micro task was recently added to the web platform and Node.js to enqueue something at the same level of promise resolved. So essentially it's equivalent of running something as a then of a promise. So essentially you can see that then one and then two and Microsoft's one and Microsoft's two are essentially the same thing. I've executed this in this at the same time. Now the next part is understanding the timeouts and the immediate. Now timeout is actually saying timeout of one. So you can set a timeout of zero, but it's actually timeout of one. So you're waiting for essentially one millisecond. And which is interesting because if we run, this is the first and then, oh, sorry, and then I can open second. Oh, no, sorry. Yeah, so I did anyway, yeah. So if I run second, you will see that the immediate is run before the timeout. And the code is the same, but then it's run after. So one before, one after. Why is this happening? So why it's happening? Well, it boils down to the Node.js event loop. And I am going to show you another piece, a magic, a very dark secret of Node.js lore, which is a guide in our docs that most people completely ignore the existence of that guy. However, it took like the Node.js collaborator maybe six months to get it shipped on our website. So you should really appreciate the depth of this guide, which is, you can find it here. And this shows exactly the values phase of the event loop. Now I'm going to stop sharing this and start sharing that. So let's see if I can make that transition swift enough. So where it is. I always point that up, a key point with all of this is to be able to understand and reason. Like I said, I've said it a couple of times, there's reason when various bits of code are actually being run. So when is a set immediate going to run? When is a next take going to run? When is a promise actually going to be resolved? And when you have multiple promises, when you have multiple of these things that are running, being able to reason about the execution order and what parts are going to impact the event loop versus which ones are not. Go ahead, Mathew. Okay, so this guide, it shows the values phase of the event loop. Now you can see that the first set of callbacks will be timers. Go ahead and increase the zoom on that, Mathew. Yeah, let me increase the zoom. Yeah, probably better. So you see that these are the phases of the event loop. So the most important one is poll. And poll is where things are scheduled. Then we schedule the execution and then are actually executed, things are actually executed from. So looking at the explanation, you see that when we do poll, it receives new IO events and it execute IO related callbacks, almost all of callbacks. So if you do a dot FS dot write on a file, it will execute there. But minus timers and set immediate. So timers of set immediate will be executed afterwards. So after poll, we almost execute, immediately execute immediate, then we use execute timers. So it's important to understand the ordering of this. So if you look at the node documentation, it says set immediate runs at the start of the next event loop. But if you look at the actual phases, the way that's implemented, set immediate's that check are actually happening at the end of the event loop turn, right? Again, okay, so the problem, the difference here is where you consider, so it's a loop. So you cannot, if it's a circle, if you pick a circle, you cannot really say when the circle start and finish. So that's the key, that's where the problem, the confusion is. So from an execution standpoint, when Node.js enters the event loopers the first time, it starts from timers. However, the next round of the event loop literally starts from poll. So you can actually, if you actually shifted this, like sidewise, it will be, you will see the behavior that would be correct, essentially. Right, this should, you know, highlight the reason why when you run first and you run second in the order, right? Why the order of the immediate's and the timers are reversed, okay? So in first, all of the code is being scheduled before the event loop starts, before that it does starts running. And what we're doing is we're scheduling timers and we're scheduling immediate's. But when the event loop starts the very first time, timer's gonna run first, right? And then it'll go do some work and then it'll run the immediate's. So those timer output will come out first and then the immediate's. In the second example, we're running from within the event loop, right? We're in a callback that is executed during poll, right? And that's when we schedule the immediate's and the timers, right? So in that thing, the event loop's already going and the very next phase after poll, after that event loop is, after that callback is invoked, is to execute the immediate's and then turn over and execute the timers. That explains why in second, right? The immediate's come first before the timers. Being able to understand, you know, reason about the ordering of those events. Good mucha. So hopefully it's okay. I don't know, maybe. Well, what's important to understand here if you look at this, right? Notice that nothing in this chart talks about next ticks or promises. So when are next ticks and promises invoked? What's the next thing we wanna talk about? And I can go ahead and- So there is a question that is timer flushed before moving to the next stage? Can you block IO by running a timer? No, you can't block IO running a timer. The only way you can block IO receiving IO callbacks or doing new IO is by actually writing a very, a lengthy block of synchronous code that will run forever so that you will change, it will block the event loop. Now- I think we could refine this, Matteo, and say that anytime JavaScript is running, anytime any bit of JavaScript is executing, the event loop is blocked, which means if you're running JavaScript, the event loop is not turning until that JavaScript completes, until it's done, and then the event loop can move on to the next thing. So let me start opening up this file. And this file, I just wanted to say, so if we do not node first, well, if we do not first.js, you see that it does the timeout and then does the immediate because it does the timeout and then it does the immediate and then vice versa, right? So that's where it does the trick. Now, if you go into second, and, oh, why the hell I'm not? What happened? I don't really understand what's happening to my setup. So if you go in here, you know, if we run second, you will see that it's actually, it shows the immediate before the timeouts. So anyway, okay. The last bit that is interesting is the mjs part. So if we go and open first.mjs, and I don't know why this is, I have something like that open, you will see that if we don't know first.mjs, it's, you will see that the microtask queue runs first, then the promise are resolved first rather than the next queue. The reason for that is that the promises, so the ECMASCII modules are loaded asynchronously and they are in a promise. So themselves they'll run within a promise and being run within a promise has this nice effect of promise. You are going to schedule a promise within a promise. So you skip staying in the microtask queue so that those will be executed first. It's also important to understand that the ES6 modules are loaded after the event loop has started. So what you're seeing here is an effect, is a change in the timing, even though the code in first.mjs is identical to the code in first.js, right? There's a change in the timing because the event loop has already started and you're running within a promise. So that's going to end up changing not only the timing of draining the microtask queue, but also a change in the timing of the immediate and the timers. Okay, so I would go back to the slide because I think it's about time we go back to the slides, I don't know. Some pinky slides, so you have some pinky slides. Do you like pinky slide folds? Hopefully so. I don't know, I would love some interaction with the audience, but you know, there is between the... We're getting plenty of chat. We're getting some good chat. We are getting some good chat. Let's go ahead and move to the next slide here. So we've mentioned a few times that the next ticks in microtask use have nothing to do with the event loop. So where do they come from? What is happening there? Okay, so yeah, in node, right? It's a JavaScript environment, yes. But that doesn't mean JavaScript is running all of the time. The node itself is written in C++. The event loop is actually a low level native C++ thing that's happening and it's turning over. What it's doing is it's scheduling some stuff out and some other threads, the IO, reading parts of a file, doing some crypto or whatever, right? It's going off and doing that some other threads. And then when those activities complete, then it will invoke a callback. That callback is actually at the C++ level. Some of those callbacks just handle everything in C++, but other callbacks actually invoke JavaScript. And what happens is you have this call stack from C++ up through V8, executes the JavaScript, that'll run for a while and then it will return back through C++ and return control back to the event loop. It's important to understand that while that's happening, while that flow is happening, like calling a JavaScript, the event loop stops, right? And the way that I've explained this before, think of it as a really inefficient mail carrier, right? So somebody, you know, if I'm delivering mail, you know, I'm going to bring some mail to Matteo. I have mail for a hundred other people, but you know, I give Matteo his mail, I have to wait for him to open it, read it, figure out what he's going to do with it if he wants to write a response or whatever else. And then wait for him to tell me he's done before I can continue to the next person to deliver their mail, right? And I can only do one at a time. That's the event loop. It can only do one callback, execute one bit of JavaScript at a time. When we talk about event loop delay or blocking the event loop, what we're talking about is running JavaScript for a period of time. Now, out in JavaScript, we have this next tick and we have this micro task queue. We're, you know, these two different queues that are built up. This time you call process next tick and hand it a function. What that does is it puts that function into a list, into a queue, what we call the next tick queue. Anytime you call queue micro task or resolve a promise, that function that's passed to then or to catch or to finally or added to the micro task queue when that promise resolves. Those are maintained in a list and as soon as control returns from JavaScript to back to C++, we have a little bit of code in node that goes out and drains those queues. All right, so anytime this call stack returns back to C++, we say, all right, do we have anything in the micro task queue to drain it? And after that is drained, right, then we continue execution. You know, we can return control to the event loop and continue. Now, one of the key things to understand about this is that this flow can happen tens, hundreds, even thousands of times per event loop tick, right? So as the event loop is turning over, right? Anytime you're calling a callback in JavaScript, you're also going to drain the next tick in micro task queue. Anytime there's any kind of any JavaScript called, you're gonna drain that queue immediately as you return control back to C++ over and over and over again, okay? And then once all that's done, once all the callbacks are done, then we can loop the, we can continue the event. Okay, you hear the event thing there? Yeah, not really. I think we are good to go. I just wanted to say a little few words here, which is that promises, remember that promises are executed synchronously and resolved asynchronously, okay? What does this means? That whenever you are calling new promise or you're calling an async function, the first execution, so when it's executing a promise, you're executing JavaScript, okay? So you're blocking, okay? You're always, if JavaScript is executing, you're always blocking the flow of new IEO events coming in. On top of that, when you do new promise, then the function you pass in is executed immediately. And when you call an async function, that is execution immediately as well. Whenever you resolve, after you have resolved the promise and you do a then or you do an await, that function will be called asynchronously, so in the future. So that's it. If you go to slide 15, we can show an example of this specifically. So here we have. Which is this is slide 15, right, James? Yeah, slide 15, yeah. So here we have, you know, these are equivalent examples. There's some details that make these different, but those aren't important at this point. But what we're doing is we're creating a promise that schedules a timer. And then that promise has resolved after the timer is invoked. So we talk about that the promise is executed synchronously, right? What we say is, you know, this in new promise, this function that's passed to it. And what this function is doing is scheduling a timer. That runs immediately. That always runs right now, right? But in this case, what's gonna happen is a promise is going to be pending until that timer actually executes on the next, you know, in the future turn of the event loop. Now we have no way of knowing how many times the event loop is gonna turn before that event loop, before that timer actually executed. It's just gonna be some time in the future, right? Once it resolves, then that then handler, that function, then that is when it's gonna be added to the next queue. And then some bit of JavaScript runs at that point, right? As soon as that JavaScript is done, that microtastic is gonna be drained and that then handler is going to be executed, right? And the async function is identical, right? You have the async function that is called. It is going to immediately invoke that set timeout, right? It's gonna immediately schedule that timer. And then once that timer executes, then it's going to execute the schedule, the next bit of code to run the microtask queue. So this, when we see in this async function, anything after an await, so you have an await, right? Anything that executes after that is the equivalent of running inside of then handler in the new promise syntax. Yeah, so here it's just an example of exactly what Mateo was just saying about executed synchronously but resolved asynchronously at some other point in the future. So we are almost 50 minutes in. We have still have a lot to go through and not a lot of time. So the sort that you are aware, be prepared, is getting worse, so. So yeah, we should go through this fairly first. Feel free to put questions into the chat while answering as we go here. But we really want to touch on this, and I can, what are promises for? Why do you use them? Like, why do they exist? Go ahead and go to the next slide then. Promises are for starting asynchronous work and scheduling code to run when it completes. To jump to the next one, what do we need to write async work, right? What we mean is a work that does not block the current event, right? So if you are using a promise, if you create a promise and all you're doing is executing synchronous JavaScript code, right, then the promise is pointless. It's worthless there, right? What you need to be doing is when you create a promise, whether it's new promise or whether it's an async function, that the thing you have to do in that promise at least once is to schedule some activity that happens off the main event loop thread, that's, you know, whether it's asynchronous IO, whether it's waiting for a network request, waiting for some query to complete, right? Something that is being handled off the main event loop thread, that's what the promise is for, is to schedule that and to start that work and schedule some bit of code to run after that completes, right? That is the only use for, that is only correct use for promises, okay? So let's go to a bunch of guidelines to get promises correctly. So one of the thing is always know when your code is executed. And, you know, if you don't know, if you don't know, please, it's very hard, study a little bit, because it's very hard. Like this is a little bit of theory that it's important, study how the event loop works, study how the microtask queue works, how a promise work. If you don't know when code is executed, it's very hard to fix certain class of bugs. Then, do note, you know, limit the use of promises where they are actually needed. So saying, for example, let's make all the functions returns a promise or let's make all functions as in functions is a really bad idea and a very quick way to slow code, essentially. It's also the way to introduce bugs in your code. And, you know, as time permits you, we're gonna be going through some examples to show why using promises where they're not expected can be a very bad thing for your application. You know, again, we're short on time, so it's gonna be difficult to go into a significant amount of detail on this, but there's several examples in that GitHub repository that go into much more detail on this. So definitely encourage you to go through that more on your own time afterwards. So never mix promises and callbacks, ever. The moment you start doing that, really, you're adding to probe, you're getting yourself into trouble. Most people get that wrong. I don't know why, but from my experience, they always get, everybody get that wrong. Either it's if it's an event emitter, a stream or whatever, that's not native, something native promise related. If you try to mix them, there will be some edge cases that you have not thought about and you need to take super care and extra care. So whenever you have to do that because there's some piece of legacy code that you cannot migrate, just create a small layer that just handles the promises part and then use that instead. And test the hell out of that specific thing. Then please don't create promises in loops. Okay, please don't. You know. You know, and keep in mind, all of these rules, there's stuff and exceptions and there's always things that's like, if you absolutely know that you're doing it correctly, then you can do these things, but you have to understand the costs. Creating promises and loops have additional costs, right? You're creating additional allocations. It's the same thing as creating objects or creating closures and loops. These are things that add additional costs and have a performance cost that is non-trivial. So when we say, don't do this, what we mean is only do it if you absolutely know what you're doing and understand what the cost is. Then again, synchronous, don't use synchronous promises. What we say synchronous promises is a promise that only executes synchronous jobs for code without scheduling anything else. Yes, never do that. Like, if you are in a point of your code where you need to use promise.resolve and you only don't have anything transaction that think a little bit about your design because you might want to change a thing or two. Another bit, which is one of my favorites actually, it's avoid long than calls. So once upon a time, there was these way of, there was this trend over like the community to use long than chains for structuring your code and doing control flow. Don't, simply put, just don't stop. The more you do that, the more work you put into the micro-sq, the more work you put into in, you more memory you allocate, you create more work for the garbage collector, it just, it's just worse. Note that having a long of synchronous than calls, it's actually not doing anything. So I'm not, it's not giving you any benefit whatsoever. The worst case that we've seen for this are folks that are using the promise syntax and then as a way of controlling code flow, not scheduling asynchronous activity. And what they'll do is have a dot then run some synchronous block of code. Another dot then run another synchronous block of code. And all they're doing is using it to control, kind of logically control, hey, I wanna do this, then I wanna do this, then I wanna do this. They're not actually using the promise for what it was intended for. And we've seen this in the wild many times. There's modules out in the ecosystem that use dot thens for this. And it really is an abuse of the syntax that all it does, the only benefit it has is to make your code slower. And I really benefit there loosely and intentionally. It just adds overhead, right? And without giving you any actual real, real benefit. Cool, James. I'm just do somebody, it's, have you got the promise map, James, can you hear me? Yeah, I can hear you. The promise map article, red link ready. Yeah, I'll pull that up. Go ahead and continue her and I'll pull up the link. Yay, so now is the time for error handling, okay? And the time for error handling is that I'm going to ask you to fill in a quick, a quick survey. I'm going to ask you to fill in a quick survey asking you what these would do. So that is actually a very, very small survey that would, you know, ask us how things are going. We're using you as guinea pigs, essentially, for our future work on Node.js. So, and it's... Yeah, that seems important. It's actually asking one of the nicest things that we can do. I'm not seeing you responding. So I hope you will respond. And, you know, while you all are taking a look at that and responding to that survey. You know, in the longer workshop, we have more time to kind of go in and understand what the cost is, you know, where you can actually, you know, run the code and compare it and see what the performance cost of these things are. Whenever you're introducing these, you know, this synchronous promises and these then handlers and stuff, like I said, all you're doing is introducing overhead to your code. We've made changes. We've gone in and made changes, you know, to say, okay, instead of using this long dot then chain, all of these allocated promises that you don't need. Refactoring that and seeing an order of magnitude improvements in the performance of code. You know, so, you know, none of this, nothing that we're talking about here is theoretical. Yes, VH and no can optimize uses of promises to an extent, right? But when you're at it, when all you're doing is adding unnecessary overhead, your code is going to slow down. Your event loop block is going to increase. The number of requests that your server can support in any one given time is going to decrease dramatically if you're abusing these things. And we've seen this time and time and time again. Some of the responses start coming in. So I don't know if you want to keep it going for a little bit more time, James, or will you just jump in and go to a solution? So there's a question in here, you know, how does unhandled projections cause a memory leak? That's actually critical to understand here in this space. And it's important to understand there are multiple kinds of memory leaks, right? Some are just like resources, you know, by themselves, they're pretty cheap. But when they accumulate, then they become more expensive. Other ones are, here's a large block of memory that just isn't being freed up. So there's different kinds. Mateo, I'm going to let you take this one. Okay, so let's stop. I'll stop sharing this and I'll start sharing my T-Max and so that you can, I can show you exactly what I mean. So we have our server as server.js, okay? This is the exact same thing of our example. Now, we can run our server. And if we run our server, I can call it. Here we go. And it goes into, well, you see here, you see what's happening? This process is not dying, is not dead, is not getting any answer whatsoever. So the problem is exactly that. So there is no, if we do not server and we can run it with curve-v, you'll see that I'm not getting a response ever. So these at some point in the latest future might time out. But if I am an attacker and I can cause the server to not giving you a response, I can essentially put your server in a situation where it cannot handle any more requests. How? Well, you need to consider that your servers have only a limited number of file descriptors that cannot locate at any given time. This limit is given to you by the operating system and or unlimited to maybe 1000, 2000, 5000, 10,000, whatever it is. Your operating system has 64K of those. So kilobyte. So that's it, that you're 64K. So that's what you have. So that's it. How do you- So in this case, every request, every request that you get, every connection that is made from a client consumes a file descriptor. Every request that comes in over that connection, right? Consumes additional resources in the form of the request object, the response object. These kind of things. So in this case, in this unhandled rejection that we have here, right? We end up in a situation where those things are not being released because the response has never come concluded. You build up enough of those, the server can't do anything else, right? So in this case- Note that only 116 requests finished over five seconds. Okay. And if I even run this for longer- So on the browser side, right? There's a lot of literature. There's a lot of kind of common practice out there that says, hey, you know what, can I handle rejection? I don't care about it, right? It's not going to impact much. Consider that the reason for that, it's a single user system. It's usually pretty safe. There's not going to be consuming resources for multiple users. But when you have an unhandled rejection on a server, that is supposed to be serving thousands, punishing millions of users, right? A single unhandled rejection, consuming resources every time and not really seeing those will ultimately have an impact on potentially millions of users not being able to use that service. So the impact of these things is much, much more acute on the server than it is on the client side. Well said, James. Well said, James. Hopefully these answers all the questions. I just want to say thank you for to guess that actually provided a very good answer in the chat and said that an unhandled rejection is not inherently a leak. But if an error happens and you don't clean up afterwards, then you're leaking, essentially. So the problem is not that, is not on the unhandled rejection itself. An unhandled rejection can be pretty okay to have. The problem is that you never know if, you know, you have cleaned up all the resources related to that unhandled rejection or not. Or if they will be cleaned up in the future because that promise could even be handled in the future. So essentially this makes it very hard to reason, this makes very hard to reason about. So essentially one of our best recommendation is if you get an unhandled rejection crash because that's the way to go. And that's the safe answer to this. Anyway, I am going to move into the next few slides. So I'm going to give you a new exercise. And it's a nice, it's another exercise about the, about error handling and about things that you can encounter doing things with the event meter. Event meter is one of the primitives of Node.js. So you might want to actually look into it very closely. Now there is a lot of things here, lot of, lot of, lot of, lot of, lot of things. So take some, take about 10 minutes and run the code in broken.js and you can see it has an unhandled rejection. Why, how, how you hand handle it and how can you successfully cooperate the error and then keep going, run all the examples up until you go and try to fix it yourself. Essentially, if you can, if you, if you don't, you can just jump to fixed and fix it better. That will give you some slight nicer things and I will give you 10 minutes to, to do this while me and James will actually keep chatting about 42. So one of the things that this example highlights and this exercise highlights is what can happen when promises are used, whether or not expected. So event emitter that it's in Node long before promises existed, its API was not designed to be able to support promises and there's a lot of, of, of code out there and you know, within Node and an ecosystem that existed prior to promises and does not have promises support. You know, if you're talking, you know, not just Node, if you're talking about the browser environment, what happens if you pass an async function and you set time out, right, and that throws what happens? You get an unheld rejection. How do you handle it? What do you do with it? You know, and, you know, how can you handle those bugs? So really got it. You really have to pay attention to where promises are expected because they're only going to be handled properly in the places that they are expected to be found. Okay, do you have anything to add to that? So definitely, you know, definitely keep going through this example and take a look. So why don't you increase your font size there? Just zoom in a little bit so we can see more of the actual code. So anyway, you know, if folks have some guesses here, you know, feel free to start putting them into the chat. What is the, what do we need to do here to start fixing this example? You know, first stop and reason about what happens when this function that does not exist is called. You know, what kind of error is that and where is that error going to go? How do we handle it? Mateo, why don't you open the still broken just so we can show this? Oh, this is fun. We're having an earthquake. Mateo, I can't hear you. I'm not sure if it's me or you. I can't hear you now. We can hear you now. Yeah. I don't know if anybody caught that. I just, you know, we here in California, we just had an earthquake here. That was kind of fun. Everything was, everything was shaking. That's good. Okay. So in the, yeah, did you open the still broken? Do you want this? You still broken file? Yeah, open the still broken file. You know, we had the interesting function and we tried catch and we, and we, and we handle that and we met error. But, you know, what, what happens in this case? Right. Yeah, for those that, you know, they don't know, event emitter has special handling. Everything's great here. It was just some fun little shaking going on. We'll have to find out to see where exactly that was to make sure that, you know, that there was no damage elsewhere, but here it was just a nice fun little role. Nice little shake. I think I got the dogs barking a little bit. That's about it. So the event emitter when you emit an error event, there's special handling in there that will say that if the events emitter does not have an error handler, it will actually throw. Right. So in this case, we have this code where we wrap it in a try and we say, okay, we're just going to afford it to emit. We still end up with an unhandled promise rejection. Right. So again, we're trying to get, but we're not actually. So I love this way. It's like, it's like so nice. It's so good. It's one of those few things that make it. Well, why did I choose JavaScript as the platform to contribute to? Well, if you want to make it even worse. Continue on. We can go. Which one do you want me to go? Do you want the better? Let's look at better because better is going to give us a false sense of security here. All right. So if you look at better, like, okay. Well, I mean, so all we have to do is add an error event handler. Right. And if you run this code, you'll see that it actually works. Go ahead and run that. It's like, okay, function, you know, cause we, you know, console log error message. It seemed like it works. We're doing fine. Right. You're handling the error. Everything is working as expected. What happens though. If inside the error handler, I throw. So open the file, but still broken. Another father called still, but still broken. Which is amazing as a way. Now that we have changed the, the, the, the event meter, the error render to throw itself, because, you know, you can actually write an error handler on an event meter to actually throw because for whatever reason, it has a bug. So. So what happens in this case, but what, but, you know, you know, you know, does anyone, you know, have a guess what's going to happen here? What happens to this new error? That is the 22nd lag. So James, you probably won't get an answer, but I can run the code. I can run the code. Go ahead and run the code and see. Still going. Yes. Nice. Unhandled rejection. So here's the thing that to under, to ask though, that error handler is not an async function. Right. We're throwing in a regular function. Why is that getting in an unheld rejection? Well, the reason James is because this is if you look at this, you are, you are seeing that this emits synchronously, which then goes in the error handler. A synchronously, which goes into the error and the synchronously, which throws, which bubbles up in this catch, which is an async function. So it becomes an unhandled and an unhandled rejection. So we're still within the promise. We're still captured or caught within that promise. So again, right? How do you handle this async from unhandled rejection? Well, let's go into, into using fixed. So let's look into the fixed one. Note that the only way to do this and have these actually not causing problems is to wrap our catch handler into a process dot next stick. Right. But here's the problem with there. If a processed next tick throws, there's no way to catch it other than to add an un, an uncaught exception handler on the process object. Right. So this is, this is very convoluted. Right. You can, I have to follow the bouncing ball, but the only way for us to actually fix this. All right. To escape that promise handling. Right. And again, we're using a promise where it was not expected. Right. So in order to catch the, the error ultimately, we actually end up having to forward everything out to an uncaught exception, or we can handle it there. It's very weird. We can do slightly better. Now we don't remember if it was fixed better or fixed once. So it's fixed better is probably the actual good solution. Yeah. So once upon a time, once upon a time, I added this option to haven't met her, which it's still experimental because I haven't got much traction and that didn't got much, much, much traction. So, but still it's there. And I plan, I hopefully plan to make that the default because it makes way more sense. Now, cap to rejection true will actually automatically attach a dot catch handler. If you are returning a promise on your event meter, which is pretty neat because this code will now work. And without the try catch, essentially, and we'll not have to do the, the try catch the next stick. It's all handled internally by event emitters. So it's way less convoluted and way less, it's way simpler to not mess up, mess it up. So in fact, we can, if we run no fix it better, we'll see that it actually does what we think it would do. All this, all this is to say though, right? It would be better to just not use promises where they're not expected. So event, even with capture rejections here, right? We have to go through this convoluted path where we have to have this uncaught exception or an unhandled rejection handler on the process objects in order to ultimately catch and handle that error. Right. And that, and we have to go through those convoluted steps because we're trying to use a promise where it wasn't expected in an API that it wasn't intended to be used for. Like if you're passing it on as in function to some, to something, they need, they need to add a catch handler to handle the exception. If they don't do that, then it's a problem. So in fact, it's a, yes, that's James Sumner says, haven't a meter plus promise equals no. That's actually. We do have a way around this. So, you know, Mateo, you're, you're, you're fixed once example there. I don't think you've actually added it to the GitHub repo. So you may need. Oh yeah, I'm going to add it. So go ahead and show that. So we added a utility with a node called once it's dysfunction called once that it basically allows us, it wraps the emission of an event in a promise. So if that event is emitted, it resolves a promise. So we've, we've taken a lot of this convoluted detail in there. And we've actually wrapped it up into a utility for you within node. So in this case, right? Mateo, why don't you show the example here and what it's doing. Yeah. So in this case, what you're doing is we are calling the run function. We are adding a once utility. We are calling once with our event meter and something. And then we await that and then we await our sleep. And then we do our function that do not exist. So essentially do not pass. Then also that is also on operators so that you can use for that that does a fork can you can use within a sync iterators or for a wait. And it on the, on the, on the events as well. So both of those approaches are actually okay. Essentially don't pass fun and asking functions to an event meter, but instead consume the event meters from the outside, the events from the outside. So with this, we can actually fix node fixed once and it actually works as we would expect it would. Okay. So let me add that thing so that you add fixed once. So we also have, in addition to once, there's also an on utility that when you have a stream of events happening, like a data event, you can consume that using for for a wait. So for a way cons. On. What we can do is let me actually try to do that. Once I can do fixed on. On. Okay. So instead of once we can use on here. And I will just go to drop all of this. And we can do for a wait. That off. On. Hopefully it would work. Okay. Now these will be the exact. On. On is not defined because. Me doing typos is actually very easy. And you see that it behaves the exact same way and it actually cleans up everything correctly. And we are actually using. On on this. So I would recommend people to use these utilities if they need to mix. Promises and a sink await. Which seems pretty interesting. James. As you see here, I see you dropping out. Well, hopefully. Yeah. I'm having some. I'm having some low system resources locally. So hopefully my audio is okay, but I'm turning off video to try to save a little bit. Okay. Okay. Perfect. Okay. Perfect, James. Okay. So you are here and so I would, this is what we would recommend people to use once or on. Don't pass something in. Or if you do make sure that you are. Using capture rejections. No. Keep mine. So there's a question. I just wanted to point out in this, you know, what block events from killing up. There's all kinds of caveats. With using these. If multiple events are emitted in the same. Next to cue batch. For a wait will only allow you to see one of those events. It'll only wait on one of them. And you'll end up missing the others. There's all kinds of issues in here. That typically when we have the full workshop, it could go into much more detail on, we just don't have time to go into all of them now. So we're trying to touch on the basics here. But I understand there are issues that you can run into. Hopefully my audio is coming through. Okay. Yeah. Your audio is perfect, James. So. Okay. I passed the link. I answered a few questions. So it's probably about. The next exercise. And then we have. Yeah. Yeah. We'll. It's yeah. Yeah. Next is a size. We have time for the next exercise. Like we still have a few minutes. So. Next is the size up. Is about what it is. Okay. It's about. Streams and Node. Yeah. So now I am one of the maintainers of Node. Streams. It's a. So the next exercise is about. Endling errors with streams and all of this jazz. Now this is actually very, very handy. Like consider this because it's a. It's actually very neat. So you should really. You should really start doing this exercise now. You have 10 minutes and it's the exercise is somehow. Is not super hard, but you know, you'll probably need your 10 minutes. And it's, it starts with again, it has a no file called broken. Better and fixed. And the broken. Essentially use mix of streams and new promise. Which we told you several times not to. Don't do these at home. Now these exercise is this. The fix for this specific exercise has nothing to do with streams. By the way. I'm just colliding two things together. The fix. The very simple fix for this is just a one character swap. You can just swap one character. You just want one character and this will run no problem. However, this will. We'll have big problems with the current things as big problems. So you can run this. Find out which single character you need to change to make these runs smoothly. And then code potentially a way better version of it. So you have more or less 10 minutes. So we'll give you a little bit of more time. Before you, you know, why are you thinking through that? You probably think it through that for the sake of time, you know, I definitely want to start working through the explanation on some of this. Keep in mind that promises execute. You know, you know, there's several different terms for it. There's chains. Or you can imagine it as a tree. When you create a promise, right? And then you have that then, that then, that then, right? That's essentially a branch or chain of these things, you know, one promise after the other schedule. Every time you call that then. Or dot catch or dot finally, right? Think about what that is. What is happening to the tree. Right. So dot then when you call it, it returns a promise dot catch. When you actually that that returns a promise. Dot finally. Also returns a promise. Right. So as you're going through and adding these things and calling these functions, like think about what is happening to the promise tree and what the code of your promise tree is. Through that tree. This, you know, what, you know, one of the nice things about this particular example. Is that it actually shows, I mean, this is one of the things that we see most frequently when, when we're going to customers and I say, Hey, we're having a problem with this. Right. Either whether it's catching bugs or even performance issues. Is the, you know, they're following the exact pattern that this example shows. And they're missing just a really simple critical thing here about what is happening in that tree. So what should we do James? We are, should we go into the. Answer or not. Yeah, let's go to the answer. So there's at least, you know, one person there in the chat that's got it. You can change one character. In this. And to fix it. And, you know, the question is. You know, with the 20 second delay here, I'll give somebody to answer. What. Yeah, the question is why. What, what, what, and what, what letter is it? What, what, what character. All right. So you can. So if you, if you, if you run broken. Okay. You will wait. I need to go into the actual folder. So push the exercises. Section three. Section two stream. Okay. So I run broken. I run broken and it tells us. Wait. Ah, yeah. So if I run broken like this, it's fine. But then if I land full bar. It will go with an unhandled rejection. Now the problem, it lies into those two lines. Okay. So essentially you are actually creating two promises. A two. Trees of promises to branches of promises. So this catch is not collected. It's not. Connected to these then. So essentially when P rejects, when the counseling promise rejects, you would have a, a one rejection will be sent down through this line. And another rejection will be sent down through these other line. So the fix is actually just replacing. The P with a space. And then we can add to this line. And then we can add to this line. So this is a case where the, the promises API, the way it's been defined is actually kind of working against you. Typically when we have an object that has some properties or have some functions, right? You know, we don't test necessarily tend to think of it in terms of creating branches, right? You're setting up a, a, you know, you're calling function on that thing, but you're always operating on the same thing. In this case, this then in this catch has the side effect. Of creating a separate branch on the tree. So it's, yeah, it works in a, in a very counterintuitive way. And how we would typically use most objects. So, you know, because of that, we see this problem time and time again, with so many different code bases where people inadvertently create trees. When they think that all they're doing is attaching a catch handler, right? To it. But it's like, no, you're, you're actually creating a whole new path. So. Okay. Now I don't like this code, to be honest. It's, it's so old school. You should not use the data event. In fact, you should actually use the new async iterators support. So if you want to receive, to consume your streams in a promise friendly way, please use async iterators. Async iterators would actually simplify a lot of these logic. So essentially you can use for a wait here. And. To actually iterate over your stream, you don't need to destroy it. You don't need to do anything for handling errors is all done by, by the sync iterator. So just use for a wait. And iterate over your stream and you will receive chunks over time. Now, after you've done that, we can actually use another method. So, essentially you can use for a wait here. And. To actually iterate over your stream. So after you've done that, we can actually use an async function for, for run. So instead of using native promises, we are actually going to use async functions. This simplifies our handling because then it's not possible to create a fork unless you use promise all. You need to create that. You need to create that in this way. You can actually, if you're going to a wait, you seem going into a straight line, which will make it impossible to have that error. So, please do do that bit. Okay. And as this reiterates the point, you know, we made earlier about not mixing promises, you know, kind of promises and callbacks, the event you met or model, it's a callback based, right? It's, it doesn't expect promises to be used. In the broken example, right? You're seeing just one of the cases where. People can easily get it wrong when they're mixing a non-promised API with the promise API, you know, without stopping to kind of think of through all what the ramifications are. In this better Fajias example, we're using an all promises based API. We're going all in on this in order to get it correct. Right? The only other option is to go with a non-all, you know, like a non-promises completely all the way through. But then, you know, the, you know, the old streams API is not the best thing to work with. So I tend to prefer this better, better to us example. So it's, we have, we are 15, we are at the 15 minutes mark to till the end. So you might want to, if you have some questions, you might want to start putting them in the chat. We'll go through them at the end, but even the delay, you know, you might, if you, the more the quicker you put them in, the biggest chance we have that we'll be able to answer them. So you see. So in the full eight hour workshop that we would do, we have a couple of exercises in that GitHub repo where we actually put some code in front of you and say, okay, convert this to a promises version. This async, this exercise five async callbacks, this is one of those, you know, how do we, you know, start, you know, working through and converting this code over. There's another one in, in, in there as well. Let's see what is the name of it. It is the convert callbacks example. It's not, it's not in a slide here, but if you look at the, at the GitHub repo, look at those. Definitely encourage you to go through those examples. Don't look at the, you know, the solution just yet. Take the time to go through those examples, do the conversion and then take a look at the, at the solution, compare it and see where you ended up. And some of these, there may, you know, there's maybe some style differences, some, you know, a couple of different ways of doing it, but the end result, you know, it should act like the solution that you have. The convert callbacks one is particularly challenging that it goes through a fairly complex, you know, callbacks based example that recur, you know, that uses recursion. So you, it may take some time to really to go in there since we don't have a lot of time to go through, we don't have enough time to go through it here. If you're doing, going through it on your own, feel free to reach out to Mattela and I, you know, directly on Twitter and, you know, or just, just find us if you have any questions or run into any difficulties going through those examples and we'll be happy to help you through it. Okay. So this is the examples. Again, if you want to follow us, ask us our email addresses are in the, will be in the slides. We publish this, this light somewhere. Also, you can ask, follow us on Twitter and tweet us, my DMs are open. Just, you know, throw stuff at us. If you ask in public is probably better. So other people can join the conversation, but whatever. Also, our emails are material.colina at near from.com and just now at near from.com. So you can actually email us if you want to. Anyway, this is an exercise of do at home. The reason for this is that if we go in here and we go section two and asking callbacks, you will see that there is the before. And you will see that this is a really, you know, nasty piece of code. Okay. Note that these are the typical pattern, which is somebody just throw. Put us in functions in callbacks because maybe they wanted to use an await in there. Okay. So there, and there, there is a question here that I'm going to leave for you. I'm going to go into some HP framework scheduling request handlers, but yeah, if you also look at the section to directory there, you'll see another example there for caching promises. And this is something that I want to touch on just very briefly, but I don't have a lot of time to go into it, but it's very common that folks, especially if they're doing wrapping an HP request and a promise, they want to cash those things. Hey, we already have a request in flight. Instead of creating a new one, I'm just going to wait on the exact same promise. This is something that's very, very easy to get wrong. And if you look in that caching promises case, look at the broken example run that and see if you can figure out and pinpoint exactly what the problem is. This is this example came directly from one of our customers that we were working with where they were ending up. They were running with a bug in production for like six months where their solution was to add a timer that ran over 30 seconds to just flush their cash out because they weren't quite sure where the where the fix was. Took a look at it and we had it within five minutes of looking at the code. We had a pull request open to fix the problem. It's another one of these very subtle changes where you only have to change one thing in order to get it right. So definitely encourage you to take a look at that example and really reason about what that changes and why. So I just want to add a little bit of parting words here. We have the question about HP framework. So I want to make sure we get. Yeah. Yeah. Okay. Let me wait. Oh yeah. Let's let me answer the questions first. Okay. So there is, by the way, thanks West to respond to express. So for all the people that will be watching the recording that have been an interesting question, which is our popular HDTV frameworks, our scheduling request handlers in relation to micro tasks, next sticks and so on. Okay. Let me give you a very run through. So express uses express registered itself to the on request, like everybody, every framework registers that and then they use next stick for middle words to ensure predictable results. Then we have, for example, happy, which is in the latest edition. It's only based on a sink await and promises, mostly a sink await. So because it's based on a sink await, it will resolve things over user. It will use a lot of promises. So these are some consequences in how you've write the code. Again, it's all based on promises. So again, it has the same concept. The latest one, which is the framework that I maintain, which is fastify. It's internally, it's uses his own state tracking and you can use both promises and callbacks and it will all work fine. So it depends. We can use either promises or next sticks whenever it's needed. So that's the first that's the hope that answers the question. Then there is another question about what about mixing a sink await and promises? Is it all when this is need to go for a complete a sink await pattern or this fight to be seen both. So I would recommend that in a same function. So when you're writing a function, it isn't promises, new promise or whatever, or it's a sink await. The moment you are mixing them in the context of the same function. So you are defining. You have in a nothing function, you are create calling a sink await. You are calling new promise. Don't do this. Okay. If you're going to, you can have another function that is returns a promise. And that's okay to use in an a sink await function. No big deal. But don't use new promise within a nothing function. So essentially don't do that. And that's actually the, the, the best, the best results. So. Mateo, I want to extend something else on the HP framework stuff. I want to look at our HP example. If you can let me share my screen. Okay. Yes. So, so one of the. New trends. Yeah. Five minutes, James, by the way. Okay. One of the new trends right now, new things to be looking at. And you know, really, this is one of the examples that I think it's highlighted by Dino. It's just using an HP server with for a wait. You know, you know, you know, using an AC generator pattern for, for this. It's important to understand that there is a very easy way to, you know, it works, right? And if you ran this code and you can play with it, it's in the repo. You can run. Oh, by the way, this is no JS. Okay. So. Yes. So you can use this pattern in no JS, but it's really important to understand that it's easy to shoot yourself in the foot with this, with this pattern. If we looked at the before. What happens if you throw an await inside that for a wait after request? Right. Which is a really natural way of doing it. My, hey, we're in his AC function. Let's, let's use a wait. The challenge here is that before wait can only handle one request at a time. One concurrent request at a time. It has to do one, then another, and then another. And by adding a wait, you basically just killed your concurrency. This particular example, if you ran it, typically we would go into much more detail is that this particular example can only one, can only handle one request per second. Period. Right. And it's because we're introducing the awaits. So go through this example, go through all the examples, make sure you understand them. And we'll go from there. Unfortunately, we don't have time to go through much more in detail. We do need to go ahead and wrap up. Let's see here. Pull up the last of those slides here. We don't do some questions and clarifications. We can kind of wrap it up. James, we cannot really see. It's very small. You need to flip your screen on the other side. You need to put it full screen. Yeah. My system is delayed just a little bit. Is that better? Yeah. Press present. Thank you. Okay. So, just kind of finish it up. Again, this workshop, it's a much larger workshop. Eight hours of material. You know, we can go through this. There's a lot of stuff in your phone can do for you. If we have any additional questions there in the chat. We'll see what we have, but we are coming up to the end of the time and they tell us that we have to stop right on time. So we can't really go over. So are there any other questions or anything else you wanted to go through? Well, we might have some more time for some more promises, weakness, whatever. I don't know, James. Why don't we throw up this? What was that? That other one that we have in the quiz. Let me open the longer version. Yeah. If you can, if you can throw that up. Yeah, I can throw that up. Yeah. Yeah. This is a fun one. Yeah. I'm just putting it on screen. Just a second. And I'm just leaving it to you. I'm just leaving this to you. Okay. So it's just a simple quiz. And you know, this is going to melt you. Here you go. So yeah, we'll leave this one for you. We're not going to give you the answer. Try to figure it out and figure out why. Cause this one's, this one's a lot of fun. This is amazing. This is an amazing thing. Really. If your brain still exists after running, fixing this. So again, all the issues that we have experienced with, with promises in a while with our customers has always come down to people not understanding how they work, understanding how to reason about them, understanding the order of execution, not understanding how they interplay with the event loop. I actually, got in an argument with one customer who just absolutely was adamant. And we used to call it new promise. That was almost exactly the same as starting a new thread. But they were coming from JavaScript. Or from Java to the Java where they were creating these threads. And so that was the rather mindset. Their mental picture was that. There's a tremendous amount of misunderstanding about how promises work. And those misunderstandings are what lead directly to performance issues. To the point now where whenever we go into a customer, if they're saying, Hey, our code's running slow, our very first question is, are you using promises? And if they say yes, the very next thing we say is you're using them wrong. We don't have to look at your code. You're, you're, because more often than not, more often than not, more often than not, more often than not, more often than not, more often than not, more often than not, because more often than not, most likely they're using them incorrectly in some way. And just by changing those, the way they're using them, correcting how they're using them, we're able to see 10, 20, 30, 40% improvement in performance, throughput, right? And sometimes even, even, even much more significantly, right? And it's not just about the execution time. We're talking about memory usage, the one event loop block requests per second, output across every dimension, just by using the promises correctly, we're able to realize performance in, for customers. Okay. Which is essentially, which is a very good way of saying this. And, you know, if you want to give me the answer, if you want to give the answer of the quiz on the chat or over Twitter, that would be very interesting to have, you know, it's, it's fantastic. You know, if, I don't know, we still didn't get, we still didn't get one and we have two minutes left. So, final questions. There was one that I answered in the chat. So that should be good. And. Oh, we got them. We got some people are about getting, giving us an answer. Oh. With a, let me go question mark. What do you think James? Yeah. So I'll say that. The, the, the, the finally three is the last statement printed. The next question for all to think about and stew on, and what we have to end with is why, why is that when the last one that comes out, what is the execution flow through here? And, and, and where do we go? So definitely hope everybody, you know, got something out of the workshop. You know, for, for having to cut quite a bit of the material out. There's so much more here that could be done. We are more than happy to do the longer workshop. You know, for you. You know, it's a, it's a commercial thing that we do in your form, in addition to solution development, we also do workshops where we touch on a number of different things. Kind of a full performance. Well, I think I'm going to be able to talk to the bottom of note. Let us know if that's useful to you and we can talk. By the way, we've stayed a little bit more in the chat. So if you have some more questions, you can, you can, we can do that. So thank you, folks. And thank you. Thank you, James for, for being my partner in, in crime for this. I just want to give you a quick thank you. quick thank you slide so thank you for your time if you need us from if you need us reach us reach us out at near form and so on so and you know thank you all and they should be really happy that we finished on time so I don't know how we this is actually formally ended but I hope it's and and somehow thank you folks and bye bye thank you both for joining we really appreciate your time fantastic thank you for everything thank you to go really well yeah that went great you had about 149 at one point but I can give you better numbers once we pull fantastic thank you fantastic yay Ray really good bye bye bye bye