 Hello, my name is Jim Schofield and my talk is what's the hardest thing timing about async? I've been working a lot with derived asynchronous data and These are some of my meditations and my thoughts working through How to get that data into components a little bit about me I'm I live in Minnesota with my wife and five kids and Golden Doodle and My background is actually teaching. I was a teacher for about eight years and then about five years ago I learned how to develop and I'm new here. I have actually been mostly in view and react and Ever is a strange land for me Like every other framework. There's a lot to get used I have come into kind of pre or post octane And glimmer so everything I deal with has been in that world and I realize there's a long history of other ways to do things in Ember and There's things like embroider resources reactor properties that we keep hearing about that I have to kind of Understand as as a stranger to this land So in my company at CrowdStrike, I Have recently been working with components that need to be loaded on any page so Unfortunate unfortunately the component has to do all the work of gathering data Now that means that I have become really accustomed to using the fetch API Now a lot of people will say why not just fetch data in the root and I wish I could but my computer my components Don't have specific roots to rely on and I can't thread data through the root My components need to be put on any page any template and they have to handle data fetching themselves so When I first came to this task, I thought oh, it's easy. I know how to deal with that I've done this so many times in view and react and The answer was to do is do it in life cycles and it all worked So with all the confidence of a somewhat experienced program I set programmer I set forth to try to create these components and I had a lot of confidence because in the ember documentation it calls out explicitly What you should do if you want components to do things on first render and they use the kind of canonical example of focusing on an element when a component loads and Inside those documents those docs you can see that they point out ember render modifiers Now I understand and render modifiers is kind of a way for you to migrate away from old ember life cycles that have been removed now So this made sense, but as I read the doc I Came across this statement We strongly encourage you to take this opportunity to rethink your functionality Rather than use these modifiers as a crutch So I Started to think about this. I in our code base I see a lot of this where there's a div and there's a did insert hook Or modifier where they would call out to do some important API work Maybe calling fetch or or something like that And I kept thinking that poor div that div has no idea that the weight of the world is resting on it Even though that that modifier and that hook really don't have anything to do with the element itself And so maybe the fact that we're placing it in a modifier is not the best place to put it so Here are a few attempts of me iterating on the idea of fetching things asynchronously and providing it to a component Now it's not important that we get all the details of what I'm saying here But I want to kind of show you the pain and the struggle I went through as I went on my path from from very beginning to absolute terribleness Working with all of these requirements So here I have my first component the get dad joke component it has a Attract property with joke and attract property to store errors You can see in the template if there's an error you show the error if there's a joke you show the joke Otherwise, you just kind of show a loading text. Now. This is not robust This is not something you would want to just do in prod But this gets the point across from my examples and then we have this method. That's asynchronous fetch dad joke That will either handle an error or give you a joke and you'll notice I call this function from the constructor So when the component is instantiated, it's going to make this call and It's going to eventually provide data through the tracked component So I have proof here that this does work Here in this video you can see that I reload the page You see loading briefly and then add dad joke appears on the screen cool We still have some questions though Like will we have to do this work every single time we want to make a request? What if the request needs to change? Let's say maybe an argument is used in the request and we need to get a specific joke By ID or search term What if that argument changes to will it react to it and What happens if that components gets torn down and there's a fetch on route? It's we should be cleaning up after ourselves. So At about this point, I did start thinking well, maybe I should use a package but I didn't So I went on to think well, maybe I can make a fetch helper and So here's my attempt number two. I'm trying to kind of make a Reusable class that can just be added to components. So this class promise handler Houses the value in the error now and it takes a promise function and in the do fetch method it It executes the promise So now all I have to do in my component is instantiate a promise handler and pass it the The fetch function or whatever promise I wanted to fetch and then I have some convenience Getters to get the data from the promise handler So I have proof here that this works. I created a toggle which will toggle this component in and out And when I toggle it in it loads and then shows the joke well So the reason that I put it in a toggle is I was starting to think well, what if a Fetch is on flight It's better But can we handle a tear down if the fetch is enroute? What if the joke ID changes still? What if it has to be passed an ID and and react to that ID and I really feel strongly that we should be cleaning up after ourselves if we have a fetch going out We should be able to abort it If we need to cancel it Now this used to be impossible only a few years ago, but we have really nice things now We have this thing called an abort controller and we want to guard against memory leaks We want to guard against sloppy practice Just like when we need to tear down and remove event event handlers. We should be aborting our fetch. So Here's the problem though This promise handler is a class a plain class and It's stored on a component that's going to be destroyed We have no way to let emmer know that this class should be torn down So how does it know when to cancel the fetch? So that leads me to attempt number three. I made a bespoke fetch helper with destruction support and that Destruction support actually has an API in ember So we can see now in our next iteration In the promise handler, we now have this register destructor up in the constructor The register destructor is taking the context and the method to run and it's saying that hey if this Promise handler ever needs to be destroyed. We should be running this dot destroy Now that's that register destructor is from ember destroyable So what's the big deal with this and why do we have this when we actually have other life cycle methods that? Could handle this well One of the cool things is not only can I register destructors on plain old objects or classes? I could instead just pass in an anonymous function and this would also work so Going back to my dad Joe component We also have another API that we need them to use here, too. It's not enough to register a destructor That's good, but we have to let ember know the relationship between my dad My get dad Joe component and this promise handler I need ember to know that hey when when you destroy get dad joke component I want you also to destroy this promise handler because it's a child of the get dad Joe component So we wrap before we attach it. We are rapid in associate destroyable child and You can look at the API for this on ember. It's under at ember destroyable Now I have proof that this is working. I had a console log in the destroyer destroy method And when I toggle this off and the component leaves you can see that That method gets run Now if I toggle in and out and in and out in the network tab also if you could see better here in this video You would see that the fetch requests that haven't resolved are actually canceled Great But what will happen again if arguments change for the component? All right, do we have a reactive promise handler and The answer is no We've done a good job of tearing things down. We have a good job of fetching things But it still doesn't react and so here we move on to attempt number four So I promise you that Although this gets kind of hairy and complicated There is a payoff. There is an answer that will make our life a lot easier. So bear with me It is possible with normal ember APIs It just I don't feel so great about it So here's a video to prove that it is indeed doable Now in this video, I I've created an input Where you can start typing search terms and you can see that it goes out and searches for That search term and gives me a dad joke Also, if you leave it empty, it will handle a little error there And by the way, if you want to see this code, this code is available at At my github jim scofield slash ember conf 2022 and I'll have that on the last slide of this this Presentation Okay, so this is attempt number four We have the get dad joke component and it's getting more complicated and the Implementation is starting to really tie itself to this component, which I do not like I want something that I can just attach easily and this is starting to not be that quickly so first of all We instead of just attaching an instance are creating a getter. This getter will run basically Quote-unquote reactively. So if arguments change this method this getter will run every time and I'm using a decorator called Ember cache decorator polyfill the link is right there. You can check it out. It's really cool So basically when appropriate arguments change, this method is run to get the fetch handler So the the thing we need to avoid though is Reconstructing that promise handler for the fetch handler every single time. This is run We actually want to update it so that we can handle destroying and Updating and stopping fetches. So we add this extra layer of a cache This could have been a private property on the Get dad joke component, but I just created a cache outside of it The idea is that if I've already created this resource or this fetch handler I want to run the update method on it instead of spinning one up and I pass the arguments to this update method but if there isn't a Resource already made We're gonna set it in the cache as a new resource. We're gonna actually spin it up So the idea is that when this component loads, it spins up this resource and ever after It's gonna actually just call update on this resource. It's not going to Spin it up again Now this is my promise handler and you can see this is just getting longer The thing that mainly changed now is that we have this new thing called update and this method so again, this update method is called when Whenever there's that that calling of this resource and And this thing already exists. So it's kind of like rec resetting the promise handler We first of all, we reset the value when you reset the error if there is on We abort any kind of fetch that's happening if it's on route and At the bottom here, we do the fetch again with a new search term there is a little bit of complication right above there because We have this await promise resolve and that's because in the reactivity system in ember Sometimes with asynchronous things you might accidentally be updating a tracked property in the same kind of tracking frame for the reactive properties and ember Actually throws an error and says don't do that because that is the source of bugs and so this is one way to keep things synchronous and What was happening here was that the abort controller was actually aborting fetches that Shouldn't have been afforded a boarded. So it's a It's a Ugly looking thing and I'm not happy with it. I think it's too tied to the component It's Using apis in the way that they weren't really meant to be used. It's really hard to debug and I just don't trust it so I Started to go back and think Well, maybe I should be using a package and That's where I came across the answer of Resources now resources are our plan to be included in ember they're Something that will be with included with Polaris and it's kind of the answer to this problem of how do we reuse functionality in this sort of way we have modifiers which have their own place and There is a thing is Such a thing as effects But those are going to be very very rare. So so these cases where we're we just need some sort of resource outside of our component This is what ember is going to be answering next Now because this is not officially included quite yet We have a lot of people who are Implementing these resources and providing it and they are stable But they're also opinions of these creators and so I'm going to show two of these implementations as solutions to your problems today and Hopefully in the future you'll be able to just pull resources out of ember and use them directly So the first implementation is ember could get used to this you might have seen this this repo out out there There's a lot of cool things inside of it But for me the thing that was really interesting was the resource class if you look at it It looks very Familiar to what I was trying to do it has a setup an update and a tear down and if you think back to my Promise handler. I had a constructor and an update and a destroy method So this maps really nicely to the problem that I'm trying to solve Here is attempt number five where we use resources and it gives us a lot of time So we have a promise handler and We still store attract value on setup We do the promise the promise the do promises basically the same as what we had before and then we have Convenient update and tear downs that let us handle things confidently Then in the component we have a lot more separation because we don't have a cached getter We use the decorator at use and we instantiate a new promise handler now in this case Because ember has a concept of positional named arguments in this particular implementation I need to pass named arguments, but that's not too important to To actually using it pretty easy to use and man after you're trying to spin up my own Things feel a lot a lot better a lot more stable a lot more dependable and There's some cool things that come along with this So if you use that resource class from ember could get used to this you have a built-in template helper this example is Used directly With that resource class that I made before and if you didn't notice that resource class is actually in the helpers directory And because it's actually also a helper a helper You can use it in the template like so we use a let statement to call dad joke helper and it provides data to us So in the template if there's a if the data is in you can prove you can display the joke And you don't need any component class to back this up Now another cool thing is there are more implementations of this resource idea and one that I really like is called ember resources this is written and maintained by nullvox popular and This is an example of using Ember resources a tracked function So the philosophy for this package is not necessarily to use a class But to kind of write a function that will basically be turned into a resource and in this case We have something called a tracked function it takes a function and it turns it into basically a tracked property every time that arguments change the arguments that are important to this function it will rerun this function and Do the fetch for you in our case? So and you can see that in the template you just have to check is there a value on this joke resource And if there is we can display it and if you look in ember resources There's a lot of things that you can use there is use function use helper use resource and then at the very end You might notice there's you ask Because a lot of people are using ember concurrency concurrency right now to solve a lot of these problems and One of the things that I think is really neat is that you can use them in tandem with resources Maybe someday ember concurrency Because it kind of inspired resources in a way. Maybe ember concurrency is going to be written as a resource But for now we can actually Use them together so this is using use task and It is using a task that's been previously previously written So if you have ember concurrency and you have tasks in your projects right now, you can actually use a resource to To call it when you need it. So in this case we do use task. We pass the task in and we pass That all we instantiate that all into joke task Now the nice thing about joke task that on the template you have these really nice Properties like is finished his error has started and those are all from ember concurrency So it gives you a little bit of of that those niceties from ember concurrency and it reloads when you need it to reload So hopefully I've convinced some that Resources are going to be really nice. In fact, you can use the idea now with some of these implementations and It's going to answer a lot of a lot of questions that people have when they're trying to deal with things Especially like with asynchronous data or reusability and functions resources allow for a lot of code reuse and To me I compare it to ember. I compare it to reacts hooks It's kind of like embers hooks you take some functionality out and you can kind of use it wherever you need it It utilizes life cycles in a way that are really easy to work with and you don't have to spin up kind of your own Hack together solutions now that we don't really have the life cycles for components that we used you It allows for better composition For example, there there is There was something I was playing with that I didn't include here But I set up a resource to go fetch a random word and then I set up a research a resource The search for a dad joke using a word And I put them on the same component and they were able to Seamlessly work together the dad joke resource waited until the random word resource got a word and then use that to do a search or a dad joke and I think above all it's just shorter to write It's a lot easier to write and there's a lot more convenience just built in for you So that's all I have again, I'm Jim Schofield at J. Scoff on Twitter I have a website here J Scoff calm and all of these examples that I've gone through are on my github repo My github is Jim Schofield a one word and then this the repo is emmer conf 2022 So thanks for coming along on this talk on resources Also, I I work at CrowdStrike and we are hiring So if you are interested in continuing to work in the emmer world with us or if you're interested and want to know more about what we Do just let any of let me know or let anyone in CrowdStrike Community know and we can talk to you about that so thanks again, and I hope you have a great rest of the conference