Simulating Slow Components0:00
(upbeat music) Okay, so we made our button component arbitrarily slow. I made it even slower. I took it out of the 25,000 iteration loop. We're just gonna do one component, pretty slow. 10 milliseconds, okay? That's what we're sleeping for. Inside of this component, we're simulating a slow component, okay? So I render this once.
we're simulating a slow component, okay? So I render this once. The benchmark says 12 milliseconds. I render it twice. It says 24 milliseconds and so on and so forth. So if I put a bunch of them, you get a lot of milliseconds because they each take 10 milliseconds, okay? So what we wanna introduce is memoization into Blaze so that we can go inside of something like a button
Defining Memoization Concept0:35
So what we wanna introduce is memoization into Blaze so that we can go inside of something like a button and type memo equals true and add on a new level of optimization that is memoization. Why the word memoization? What's the difference between memoization and caching? Maybe you never even heard of the word memoization. Memoization essentially means caching. You're caching something.
Memoization essentially means caching. You're caching something. But instead of putting it in a persistent cache that lives in a database or something like that or a file, memoization is just in memory. It's just something that lasts for the duration of a request. So this can be as simple as a protected property in a class called memo that you write to like this arrow memo, you know,
in a class called memo that you write to like this arrow memo, you know, foo and then equals bar. And then later on, you check to see if memo has foo or something, you understand. But we're gonna call it memo, but for this example, we're actually just gonna use Laravel's caching mechanisms because it's basically the same thing. Okay, so let's do that.
Using Laravel Cache API1:28
because it's basically the same thing. Okay, so let's do that. Before we add it into our compiler, we're just gonna basically wrap this in some caching to see where we're, what we're trying to do with the compiler anyway, all right? So again, right now you have a bunch of these, it's pretty slow, but we can cache these, okay? How would you even cache something like this? Like you're probably familiar in Laravel,
How would you even cache something like this? Like you're probably familiar in Laravel, like if you do like cache, remember, forever or something, whatever, you can do cache has, cache get, cache put. If you get cache, remember forever, you pass some kind of key like, hey, and then a callback like this. And then usually you're caching like eloquent models or something, user colon, colon, all or whatever, I don't know.
eloquent models or something, user colon, colon, all or whatever, I don't know. And then you get the result here like this. And then the first time it's hit, it checks. Every time this code is hit, it checks to see, hey, is this key in the cache, if it is, then let's just return it directly and not run the closure, the callback. If it's not, then hey, let's run the callback, get the value, put it in the cache
If it's not, then hey, let's run the callback, get the value, put it in the cache and return it from this remember forever call, okay? So this is the cache mechanism that we're gonna use. I like remember forever better than the, you know, has pattern where you say like, if, you know, cache has then return and then else or whatever like that, then you store the output and you put it in there, whatever. I think, I think this is really elegant remember forever. So that's what we're gonna use, okay?
I think, I think this is really elegant remember forever. So that's what we're gonna use, okay? But you're used to seeing this in PHP where you can just return some PHP code. What about when you're using it inside blade? Like we're inside of a blade or PHP template. Like how do we take this and make this output, the thing that is cached anyway? Well, it's, it is a little bit weird, but you can do it. We can dance in and out of PHP.
Introducing Output Buffering3:06
Well, it's, it is a little bit weird, but you can do it. We can dance in and out of PHP. So let me, let me comment this out, okay? And I'm gonna introduce you to something called the output buffer. I don't know if you've used this before, but when you're dealing with stuff like this, like in blade views and things, it becomes very useful. Laravel uses it a ton internally.
it becomes very useful. Laravel uses it a ton internally. Basically PHP, whenever you do this, like let's say echo high, okay? Yeah, we're gonna go first principles here, or comment everything else out, load this in the browser, it says he, okay? We just echoed that, perfect, right? Okay, now if we just type he instead and we load it, it shows up just the same.
Okay, now if we just type he instead and we load it, it shows up just the same. When you have something just in plain PHP, it internally is echoing. So this is kind of the same thing when you echo or when you have something right in here. And all of this stuff goes into an output buffer. It goes, actually goes into the output, like straight to the browser, we'll say in theory, but you can buffer the output.
like straight to the browser, we'll say in theory, but you can buffer the output. So there's functions in PHP, output buffer functions that start with OB that basically say, hey, we wanna catch any echoes and put them in a bucket and then let you do whatever you want with them. You can collect them, you can put them into a variable, you can pause and like hold them all and then let them all go onto the browser.
you can pause and like hold them all and then let them all go onto the browser. So I'll show you what I mean. If we put another PHP statement up here and we say, OB start, we're saying output buffer start. Now anything in here is gonna get collected and then at the end, we could do like OB clean. And what that's gonna do is throw it all away. It just trashes it into the ether. We could do get clean and store that in a variable
It just trashes it into the ether. We could do get clean and store that in a variable like foo and then later on, we could do like echo string to upper foo and then echo that out and you get he-hee, okay? Does that make sense that foo is now a variable that contains a string of anything that's been outputted since here, okay? So that's output buffering. OB start, OB clean, it's just buffering any output,
So that's output buffering. OB start, OB clean, it's just buffering any output, putting them in a bucket and letting you do whatever you want with it. So we can leverage that like in this scenario. We can say, let's actually bring back this, okay? And let's turn this right into PHP. So we go into PHP and we say echo, cache remember forever, we'll keep the key hay, okay? Function and then we'll pull this into the function, right?
cache remember forever, we'll keep the key hay, okay? Function and then we'll pull this into the function, right? 'Cause this is effectively what we wanna do. However, you can't just stick that inside of PHP. We have to do OB start, okay? Then end PHP, then we can do whatever we want, just normal stuff here. Then we can call, we go back into, yeah, back into PHP and we'll return OB get clean, okay? Now, if you're not familiar with output buffering
and we'll return OB get clean, okay? Now, if you're not familiar with output buffering and dancing in and out of PHP and what works and how it works, this may seem a little bit crazy, but I think you get the idea, okay? So we save it, now look at what gets compiled. Our same thing except it now compiles that require statement. We get an error unclosed curly because what did we do? We need to close the curly and then this and this. It should work, but oh, this is my problem right there.
We need to close the curly and then this and this. It should work, but oh, this is my problem right there. Okay, let's try that again. Okay, the benchmark ran, it works in the browser, okay? Now, if I duplicate this like three times, notice the benchmark is still the same time, but there's three buttons because each time we're saying the first time we're going, hey, remember this forever, the second time we go, hey, this already exists, let's not run this at all.
hey, remember this forever, the second time we go, hey, this already exists, let's not run this at all. We're not gonna run this closure at all. So is this clicking? I know it might seem a little bit weird and like wizardry, but when this stuff starts to click, you should start to see how, oh, with output buffering, we can capture things and pass them around at different areas. This is how slots work in Laravel itself. Slots use output buffering to gather the contents
This is how slots work in Laravel itself. Slots use output buffering to gather the contents and pass them as a variable into another component with just the dollar sign slot variable, right? Okay, so we have the concept down, we even have the code down, but what we don't have is this automatically working inside of our compiler. So let's make that work. Let's go into our button and look, I already did it.
Adding Memoization to Compiler7:13
So let's make that work. Let's go into our button and look, I already did it. So we have atblaze memo true, okay? This is gonna be the thing that signals to our compiler that we do wanna use memoization and then we'll add all this stuff by hand here, okay? So let's maximize this window here and then we go into our compiler and we scroll down and we say, okay, match should optimize. Yep, we still wanna compile the component
and we say, okay, match should optimize. Yep, we still wanna compile the component 'cause we always need at least one to render to go into the memo, okay? But now here we wanna do something a little bit different. So what if I do this? What if I say output equals? But now around here we can wrap this output in all that memoization code in a conditional. So we can say if this should memoize
in all that memoization code in a conditional. So we can say if this should memoize and then we could pass in the path like we did before for should optimize, then if we should memoize, let's actually do that right now. So let's just duplicate this method down here. Then instead of optimize, we'll say should memoize, we get the contents and this is pretty fragile but this is what we're doing for now. If it says blaze memo true,
but this is what we're doing for now. If it says blaze memo true, if this string contains that, then we'll say should memoize equals true, okay? The end we're gonna return output and now inside here we can decorate output with some stuff. So check this out, let's do PHP, PHP. And now let's grab all this code from over here, okay? Go back into here, pop, pop, pop, change the indentation, okay? And then all of this should be pretty good.
Go back into here, pop, pop, pop, change the indentation, okay? And then all of this should be pretty good. We're gonna need an arbitrary cache key, which we can do. So let's do this key equals and we could just use that same hash. Do we have the hash? We don't have the hash. We could use the component name, I guess, I don't know, component dot and the name, that's fine.
We could use the component name, I guess, I don't know, component dot and the name, that's fine. It doesn't really matter as long as it's unique to the component, okay? And then we'll do key so that we're remembering forever that key. Then we have output buffer start and then this here, we want to replace with this bit here with our output. So we should be able to just do this, okay? We'll get rid of those new lines
So we should be able to just do this, okay? We'll get rid of those new lines and everything should be good. I kind of wonder if this will work, fingers crossed. All right, so now let's get rid of all this stuff. Okay, hit save. Ooh, undefined constant component. So I didn't wrap this inside of a string, so it's giving us an error. Let's try that again.
so it's giving us an error. Let's try that again. Hey, it worked and look what it compiled to. Perfect, so now I can have like a bunch of these. They all load in the browser perfectly well and you can see how they all get compiled. You can get compiled down here to this cache. Remember, forever component.button, that's the key. Then OB start, require that thing directly and then return OB clean.
Then OB start, require that thing directly and then return OB clean. And then let's just like triple check this. So if I remove this, it gets rid of all that caching, okay? And now the whole page takes like 100 milliseconds. If I remove this, it goes back to just normal blade compilation or whatever, which is slow. We can add those back in and get the memoization stuff. So how awesome is that? That is how memoization works in Blaze, literally.
So how awesome is that? That is how memoization works in Blaze, literally. Like we just have our own little memo thing inside Blaze that has the same methods like has and get and put and whatever, but we set a key and we use the output buffer and we capture the thing the first time and then we use it again if it matches later on. This was the first level of optimization that I thought to even do when I first started thinking
Avoiding Cache Key Collisions10:46
This was the first level of optimization that I thought to even do when I first started thinking about how to make blade faster. The one thing that we should note though, that we didn't cover at all is right now again, this is a toy. So we haven't, we don't support, you know, props, but let's say we did and you had one component that was Fubar and the other that was Fubaz. You don't want these to, you don't want a cache collision.
that was Fubar and the other that was Fubaz. You don't want these to, you don't want a cache collision. You want these to be on separate caches. So what we do in Blaze is we create the cache key based on the name of the component and all of the arguments to the component. We create one hash based on that. Now that's the key. Now you're never gonna like run into a situation where this one caches and then this one doesn't
Now you're never gonna like run into a situation where this one caches and then this one doesn't or this one overwrites that cache and then you have two of the same thing when they shouldn't be, but that's it. This is how memoization works. And now you have a full deep understanding of memoization inside Blaze. Let's go to the most fun optimization folding. I'll see you in the next video.
Let's go to the most fun optimization folding. I'll see you in the next video.
