 you everyone for coming. It's very exciting to be here. I hope you're all enjoying the conference as much as I have. I'm going to start off by letting you all in on a little secret. And it's that I am very much more comfortable in front of a computer than I am doing any sort of public speaking. So we'll start off by telling you a little about myself. My name is Kelly Senna. I'm a web developer at Big Nerd Ranch. We're consultants. We also teach and rewrite books. I personally like to stay on the consulting side of things. So I get the great opportunity of getting to work on a lot of different types of technologies and applications and businesses. It also means that I get to work with a few different frameworks. So when I first started telling people that my talk was going to be about memory management, the immediate response was almost always the same two questions. The first one being why. And the second usually in form of a sanity check asking if I had forgotten what programming language I was using. But here we are at EmberConf talking about memory management. So I'd like to share with everyone why I feel like this is still an important topic today. And the main one of those being user experience. So we're not guaranteed an internet speed across the country or across the world. So we have to deal with limited internet access or varying connection speeds. But even if your users do have the best internet access, what is the chances that they're going to have to share that connection, either at home, at work, or at a conference like this? So the connection speeds here might typically be good on any given day. But now that we have a thousand people trying to download cat videos, things probably start to slow down a little bit. Hardware can also impact user experience. So you're not guaranteed that your users are going to have the latest and greatest laptops and desktops, including my own until a few weeks ago. I was working on a MacBook that was a few years old. But if you insist that your users have great internet access and have great hardware, let's talk about your user habits. So how many people in this room have at least 10 tabs open in any given browser? Yeah, myself included. So we're web developers. That's what we do. We do things on the internet. But that's not all that we do on our computers. We're checking emails. We're listening to music. We're streaming videos. And then we're actually working. So we have text editors and terminals open. And we're deploying code. And don't forget about debugging in the browser, plus all of your browser extensions. And every single one of these things uses memory. So as developers, why should we care? And the easy answer is that even modern browsers are not exempt from performance concerns. So my old computer crashed all the time. And the biggest culprit was browsers. But another reason this topic is important to me is because of a few teaching experiences that I've had over the past couple of years. And I've had the opportunity to work with a lot of new developers. And it's been so much fun and so educational for myself. Some come from CS backgrounds. Some come from nontraditional backgrounds. But regardless, they all ask questions like, why am I writing code this way? Or why shouldn't I write it like this? Or why can't I just use this library that says it's going to do everything for me? That's why knowing how things work under hood, knowing how code you've written actually works, or what all of those libraries are doing for you, can help prevent disasters. So having a stronger understanding of those underlying technologies can make us all better developers. And also be able to make more informed decisions. So before jumping into how or what code to write, we're going to start at some of the basics. So we're going to start with the memory life cycle. And it's pretty straightforward. And we can sum it up in about three steps. Allocate, use, and release. So lower level languages, C being a common example, all have built-in primitives for allocating and deallocating memory. But in JavaScript, this is done automatically. Values are allocated when created and freed when they're no longer used. And this automatic process makes it easy for all developers to feel like they don't need to care. But we can still create objects that stick around after we're done using them. So I think a good example is to actually look into what's happening with this automation. And the first step is that you actually need to allocate the memory you need. And in JavaScript, this is done alongside object creation, like declaring variables. But function calls also result in object allocation. And some methods will create new variables or objects. And then you actually have to use it, which is basically just reading and writing the memory. Both allocate and use are explicit in all languages. And in JavaScript, when I say explicit, it's meaning that you actually have to create these variables. Your code won't just know that you need a variable called enterprise or that it's going to be a spaceship. And the third step, release, is this process of deallocating the memory when it's no longer needed. And this step is also explicit in lower-level languages. But in JavaScript, this is where the garbage collector comes in. So all browsers handle garbage collection a little bit differently, but most modern browsers will utilize a generational and a mark-and- sweep garbage collector. So taking Chrome's v8, for example, we have a... So generational garbage collectors leverage the fact that most of our objects are meant to be short-lived. Usually, you're not going to have a lot of global variables hanging around all the time. So objects are generally gathered into two groups. And we're going to refer to those as young and old. So the newest objects that you create, they're going to be allocated to this young heap, which is on the top. And when this particular young heap is full, a young garbage collection is triggered. And if any objects are still deemed alive after this, and by alive, I mean, still being used or referenced, they'll be moved to the next generation. And young garbage collection happens more often than old. And we'll see why this is a little bit faster of a process in a minute. But old generation collection usually uses a mark-and-sweep algorithm that's based on the idea of reachability or references. So in old garbage collection, or old generation, the garbage collector will start at the global object or root. So for example, that could be the window object of your browser. And from there, it will look for any objects referenced from that root. And then it will continue to look for any objects referenced from those objects, and so on, pretty similar to a tree structure. And when an object can no longer be reached from that root, it will be considered garbage. But the thing to keep in mind is that when an old garbage collection starts, a young generation collection will also run. And that's one reason why it's a much slower process than just young collection on its own. So garbage cleanup is a very important part of your performance. The collector is your friend, and it's designed to make your life easier. But it's still important to understand and implement effective memory management, because it's not only about how many objects that you still have in memory, it's also about how you allocate and use. So while having this type of automatic management is great for developers, the browser's collector does not know your applications or your intentions. So your code should be very clear about what you want to do and what is no longer being used. So if we don't have the same primitives as low level languages, why should we bother learning about memory lifecycle? Well, as we mentioned earlier, even modern applications and modern browsers still have to deal with bloat leaks and collection pots. So what happens when you run into a memory issue? You have slow UIs, you can cause reduced battery life, because your laptop is now working harder, or your browser can crash, and none of your users ever want to see this baked. So most tips that you read online about memory leaks are about how to avoid things that prevent the browser from releasing memory. But some of these problems can also be caused by we as developers are doing. Some of those things include the misuse of variables. So if you're creating a lot of global variables, they're not going to be cleaned up until a user refreshes, closes your tab, or closes the browser, or navigates away from the page. So if a variable is scoped, this global object, your garbage collector has no way of knowing unless you explicitly null it out when it's not going to be used anymore. But when you use local variables, they're going to be cleaned up when the function has completed, and there are not any remaining references to it. Another thing that developers can cause is just creating too many allocations. And then your user is going to experience all these garbage collection pauses. So you're going to have that slow UI. And we can also have callbacks that are waiting for something that never happens. Also DOM changes are very expensive memory actions. So if you're manipulating the DOM, you can typically get better performance by trying to batch your operations together. So memory leaks still happen every single day. I still see them to this day if I'm doing any code reviews. And we're under deadlines and you're trying to write code fast and sometimes a few things get missed. And usually only the ones that cause big changes in performance are the ones that get noticed. But even the small ones can add up, especially in single page applications that we're starting to build. The browser's job is only to reclaim things that are no longer reachable. So this is meaning if you're accumulating objects and you're not removing them when you're done, memory usage continues to rise as the amount of objects increases. And there's nothing the browser can do about that. So just be proactive about preventing these issues. But there's no single right way to do things. So don't get too focused on optimizing that you forget to solve your real business problems. Just keep in mind that if you want better performance for your application, you should be writing code that is faster, more memory efficient. So we've discussed a lot about memory and just the basic life cycle. And now we know that if we write clean code, our apps will be more efficient. And at this point, you may be thinking, if I know how to write clean JavaScript, why do I need a framework like Ember? Well, if you've ever built or tried to build a complex application with a lot of user interactions without Ember, you'll know how difficult it can be to manage data in UI as it begins to scale. So for example, in regular old JavaScript land, it can be hard to know when to remove event listeners. And ideally, you'll want to remove them when you take a thing off the screen. But to write really performant JavaScript, your UI has to be built up using some type of setup, interaction, and teardown cycle. And then you're going to want to find ways to streamline your code and how it interacts with the DOM. And then you're going to want to try to find ways that your code can be easier to write, test, and troubleshoot. And now you're basically building framework. So we decided to use Ember in a few production apps because these projects really needed an opinionated framework that would help reduce some of the boilerplate JavaScript. Ember has a lot of great features to help you build a clean interface. And it's optimized exactly for rendering data to the DOM. And it helps enforce great coding patterns. And this was very, very helpful. And developer onboarding and resulted in so much less bike shedding on how to actually do something. And these are a lot of nice to have, but what does Ember have to do with memory? So one really good example of how Ember helps optimize this for us is with built-in events. And these events include common key presses and mouse events. And instead of having to register these events manually, Ember sets up a global event listener. And after Ember first initializes, all Ember code is run in response to these events. And the great thing is that if an event does occur, Ember will look at the target, if say a button click, and it will travel up the DOM tree to find the corresponding method. And this is quite a bit easier than having to manually find the elements ID. So when one of these event listeners is triggered, an Ember run loop is started. And this is one of the things that I think is really neat about Ember. So Ember schedules work by a set of cues, also known as the run loop. And by default, there are six. And all of these cues have a priority and they're processed in order, with sync being the first and the shory feeding the last. And the run loop helps optimize our callbacks by combining and ordering our code. And it helps coordinate some of the changes to the DOM. So one of the biggest efficiency boosts that we've seen from Ember is this ability to coalesce these multiple events. Otherwise, we'd basically be trying to do them ourselves or we would just have to deal with it. So all basic user events, like clicking a button, will start a run loop. And this guarantees that change is made to any properties by this event are propagated before returning control back to the browser. So we have all of these, so we have these six events. And they kind of just look like words. So maybe we'll step back and just kind of run through actually what they do really quick. So your sync cue is the first cue and it's also the first priority. And this is where your data bindings are handled. So because the run loop is triggered by user interaction, like entering text, we are going to need these new or updated values before anything else so we can keep our objects in sync. And actions is your main work cue. And that's where any and it contains any scheduled tasks. And it's like any of your async functions or promises. And before rendering anything, Ember will attempt to promise any route transitions. And this helps make sure we don't try to render anything before we are that we're going to immediately navigate away from. So render cue is when Ember begins to generate that updated DOM. And because this occurs after all other changes to our data, this can help ensure that our DOM only has to be generated once during this run loop. And that's great because our those repaints and layouts can be kept to a minimum. So the after render cue contains jobs that need to happen after your DOM has been updated or generated. This is commonly used for like jQuery, D3 or any other third party DOM manipulations. And the last one is destroy and it does pretty much what you think it's going to do. It contains any jobs to clean up objects that have been scheduled to destroy. So there was a lot of information that I just threw at you about the run loop. It's going to be hard to take it all in with me just talking at you. So I kind of built up an example to try to show you what it looks like. So when you start a run loop, it's going to be again with a sync queue. And when that sync has completed, we move to the actions queue. So here we can see that there are eight tasks queued up. And once those tasks are completed, the run loop will step back and see if there are any additional jobs in the previous queue. And if so, it will process those before moving on. So once those are completed, and if we have any tasks in the router transition queue, any guesses? Yeah, we're going to back up and make sure that no additional jobs were added to the previous queues. And so on until all of our queues have been completed. So if you're still a little bit unsure about how this works, it might make more sense with an actual example. And I found that components are pretty good for this. So if you're not familiar with components, they allow you to create reusable pieces of code that extend HTML standard, which means that they can be used as first class elements. So not everything has to be a div. So you can have A tags and UL tags and LI tags. And components are great because they help solve the problem of duplication and lack of encapsulation in front-end web development. But the behavior of a component is controlled by JavaScript and can be customized with event handlers and their lifecycle hooks. And these handy lifecycle hooks allow you to run tasks at a different point throughout your component's life. And they occur upon initial render, re-render, and destroy. So if we know when they happen during the render cycle, we can also dig in to see where they're handled in the run loop. And this is usually in the render and destroy. In lifecycle hooks, all you allow also allow you to be more explicit. So we've used components for things like date pickers, determining the size of input fields, using the dead insert element hook. And we even use them during to do horizontal scrolling using the embers run loop. So I have a quick example. This is a fairly simple example for just showing and hiding an image. So in the component, we have an attribute called is showing image. And when you press the button to show the image, the attribute is set to true and a run loop begins. And as we can see when logged out, all of the dominate manipulation is being done in the will update hook. And it's also handled in the render queue. So another thing about another great thing about components is that Ember will tear them down during the destroy queue when a component is removed. So you don't have to manually tear these things down. So let's say we had a more complicated component. We might want to have certain behavior happen after a property has been changed. And just like in JavaScript, Ember observers are mainly used for reacting to changes. And you can still create your own observers manually in Ember, like in the dead insert element hook in the component. But you also need to make sure you remove them. But if you use Ember's built-in syntax, it will automatically tear down the observers when the object is destroyed and this helps to avoid memory leaks. Chases are, if you need an observer, you may just be able to use a computer property. So computer properties are built on top of the observer pattern and it's great that they can be defined as functions because then you can use it the same way you would any normal or static property. And they can also be used in templates. So with computer properties, when it's first called, the result's cached. And when a state changes occurs on one of the dependent keys, it'll recalculate the output. But if no changes occur, then the cached result is used. Because the computer properties observe the properties that they depend on, this means that you don't have to manually make sure everything is in sync. So when writing a web application, knowing how to use Ember is like working with this organized and calm and easy set of operations. You kind of feel like you can sit back in the commander chair and kind of code with a feeling of safety. It kind of makes things look easy. But as a developer, you should really have detailed knowledge of how Ember and the underlying technology works, so you can really take advantage of it. And now that we know a bit more about the memory lifecycle, we can start to utilize a few basic JavaScript best practices for letting the garbage collector do its thing. So Ember has a lot of built-in functionality that allows us to focus less on boilerplate JavaScript and more on solving real-world problems. But having built-in events and being able to use the run loop and even lifecycle hooks help make our applications more efficient and they provide great coding patterns and they save a lot of developer headache. But these examples and these components and their lifecycle hooks are only a very small few examples of how Ember helps simplify some of our common JavaScript. The big takeaway that I want you to have from this talk is that having this type of automatic management and helpful frameworks is really great for developers. But be mindful of the underlying technologies and write code that helps the browsers garbage collector collect. So if you have any questions I'll be around the conference the rest of this afternoon tomorrow. I also have built the example application that has the console logs similar to ones that have been in these examples that you saw with debuggers. So if anyone wants to pair and kind of dig into the run loop on some of these queues I'll be happy to hang out later this afternoon and also be posting to GitHub. I also have some big nerd range swag if anyone wants some. Other than that, thank you so much for coming.