 So my name is Justin Fignani, and I work in Chrome on things like web components, Polymer, and Lit.html, and right now I'm going to talk about the virtue of laziness. Next slide, advance. Today is the day. That happened? Yeah. Okay. So we're going to look at how to do less, be lazy, and take breaks, and end up with a better web application for it. And when I say better, I'm really talking about four overlapping goals here. We want to deliver great user experiences, and we want our apps to be fast and to respond quickly to input and changes. And more than just making fast apps, we're making it possible to build fast apps. We want to make this easy, so easy, hopefully, that it's the default, because this is going to make our users happy, our developers happy, and happy developers will make better user experiences in the long run. So with these four kind of general goals in mind, I'm going to walk through several techniques for leveraging asynchronous programming for building better UIs. So we're going to look at batching work for better performance and developer experience, keeping our UIs responsive with non-blocking rendering, managing async state for a better user experience and developer experience, and then finally coordinating async UIs once we have all this asynchronicity throughout our application. And this makes for a handy little talk outline right here, so I'm going to give some background and then jump right into it. But first, a quick note, this is day two of the Dev Summit, so it's a little more future forward-looking, you know, and the stuff I've made here, the demos and helper code, is a little bit experimental, but it's only using current browser features, and so all of these techniques still work today. So now for a little background, I mentioned that I work on web components and I'm going to call it HTML, so we're going to use these things as the basis for the demos and the talk. So if you haven't used web components before, web components let you define your own HTML element tags. So it really refers to two specs here, custom elements and Shadow DOM, and combined they let you define your own tags with custom implementation and UI. So to create a custom element, you simply extend from HTML element, a built-in class, you add your implementation, and then you register your class with a specific tag name with the browser, and from there you can use this element in that tag name anywhere you can use HTML, so in your main page document, inner HTML, document create element, even in other frameworks. So next, Lit HTML. So Lit HTML is a way to write declarative HTML templates in JavaScript, and we use tagged template literals to write them. This is a feature that came out in ES6, and these are strings that are denoted with backticks instead of quotes, and they can have a template tag in front of them, and we're going to use the Lit HTML template tag here, which is just going to allow us to process this template to make it more efficient, and then inside of our template, we can have expressions, and these are just plain JavaScript expressions. Once you have a template, if you want to render it to the DOM, you simply pass it to the Lit HTML render function and give it a node to render to, and it's going to make that DOM appear there. And the nice thing is that if you call this render function multiple times of the same template with different data, Lit HTML is going to take care to only update the expressions that changed. It will never update the rest of the DOM in the template. And then finally, if you take web components in Lit HTML and combine them together, you end up with Lit Element. So Lit Element is a convenient way to write web components, because this is day two and a little more forward looking. I'm using some future JavaScript features here, like decorators and class fields, and Lit Element really gives you two features. One is the ability to declare observable properties. So these decorators here are going to create getters and setters instead of a field here, and the setters are going to recognize when this property changes and then tell the element that it needs to update. The other feature is that it lets you write a render method that returns the Lit HTML result. And so when the element knows that it needs to update, it's going to call this render method, take the result, and render it to the shadow root of this custom element. And then finally, we give you a little helper here, so you can use a decorator to register the element. So once you do that and you create your element, then you can use it anywhere you would HTML, and it will render as you expect. So that brings us to our first technique here, which is batching work. And if we go back to our element definition, we'll see in the render method here, this is called force automatically by the lit element base class. But the question that comes up here is when is this method called? So to look at that, let's take a look at a little example here. We're going to use this element imperatively, but this also applies if you used it in the main HTML or if you used it with a framework. So we're going to create an element instance, and then we're going to set a property. So the question is, should we render now? We could render now, but we don't know that we're not going to set another property right after we set this property here. And if we did render after every property set, we would be rendering multiple times potentially for every element as we update the data. We don't want to do that, so instead, we're going to enqueue a task. And then in the future, that task is going to run and actually render the element. And so that we know when the element has rendered and when it's complete, we add this promise hanging off the element here called update complete. And this is going to resolve when the element has rendered, and if you wait for it, you know that you have a fully rendered element. And the way that this works is we have an asynchronous update pipeline under the hood and lit element. So when a setter is called for a property, it's going to call this request update method. That's going to schedule an update task, but it's only going to schedule one if there isn't one existing. If there is one, we're just going to use that same task, and that's how we get the batching. When that task runs, it's going to call the update method on the element, and that's where the actual work is done to render to the DOM. So we do this for two reasons. One is performance, like I mentioned, and the other is developer ergonomics. So if we go back to the template here, we see that this template renders two different properties in the same template. And it's much easier to reason about these templates if we don't have to worry about the order in which these properties are set or whether or not they've both been set together or not. So we'd like to take all the changes that are incoming for an element, batch them together, and then let you write a simple declarative template to render your element. And so an interesting implication of this is that lit element rendering is always async. You never opt into being async, and you can't opt out to being a synchronous. And when we explain this to people, sometimes we get a question, won't the UI partially update? And the answer is no, and I built a little animation here to try to show this. So here we have a tree of elements. Let's assume these are all lit elements and they're passing data down the tree via properties. And so that's our component tree. And then right here we have the microtask queue. So hopefully in other talks they've talked about this, we have a queue of microtasks that the browser runs through to completion before it will paint or handle user input. The yellow box here is our current microtask. And so if we have some code that runs that's gonna set a property on A, that's gonna cause its microtask to be in queue. And then when A gets to run, it might set some properties on B and C, so their tasks are gonna be in queue. And B is gonna set some properties on D and E, C is gonna set some on F, and so forth. And we get to run through this entire queue until it's empty. Once it's empty, then the browser can paint. And to show this with a demo, I made a demo here of a tree of elements and each one takes an artificially long time to render. And so normally, you might expect, if you don't know how the microtask queue works, that these might paint in individually. And we'll see here that if we click the render button here, that they all snap in at once. So even though each one takes 50 milliseconds and the whole thing takes 750 milliseconds, we don't see the intermediate states. And this is great if your UI is painting fast, if it's not taking 750 milliseconds. But if your UI, if you have a very complex tree and your UI is rendering slowly, then we've just introduced jank, which we don't want. So this brings us to the next technique, which is non-blocking rendering to keep a responsive UI. So we just saw that we can have async rendering, but still block paint and input. And we know we can have complex UIs that take a long time to render. And we know we need to render in less than 10 milliseconds to keep our 60 frame per second target. And one way to look at this is that we have all these microtasks here in the blue rectangles and they kind of fill out a complete task and this task blocks rendering. And as long as the complete task fits within our 10 millisecond budget, we're fine, right? But as soon as the task exceeds the budget, we're gonna introduce jank. So our technique here is to break this up so that instead of having a whole bunch of microtasks in one long task, we just give a task per component to render. And now these will hopefully fit in under 10 milliseconds and we will get smooth updates. So the way we're gonna do this is we're gonna tap into this asynchronous update pipeline that LitElement has. And we're gonna customize the schedule update task step right here. So that brings us to our first experimental helper that we're calling for the moment, lazy LitElement. The way that this works is that under the hood in LitElement, there's a method called schedule update. And by default, this thing just waits for a microtask and then it calls validate which does the work of rendering. And so what we do in lazy LitElement is we override this and instead of waiting for a microtask, we wait for a promise that's resolved on set timeout timing. It's a very simple thing to do, but it lets the browser paint and handle input before we render. So now if we go back to this demo here, we can turn on lazy rendering. And now everything's gonna render on set timeout timing and you can see that we paint the intermediate steps here as we go. And so we've reduced shank and by showing some intermediate state. And so a lot of frameworks have been working on asynchronous rendering over the years and especially React recently. And they have created a demo that I quite like which is a Sir Pinsky triangle demo. And the way this works is that you have a large tree of components here and each one of these has also been written to take an artificially long amount of time. And they all have a label and this label represents data flowing down the tree. So to update the label on all the components is gonna take a little bit of time. And while we're updating the label, we're gonna animate the size of the tree and we want this animation to be smooth and it's driven from JavaScript. So if we take a long time to update the tree, we're gonna get jank. This is a nice demo because it highlights some subtleties that you need to take care of when doing asynchronous rendering. So we have an expensive sub tree to render. We want this continuous script driven animation to be smooth and then on top of that we have these high priority inputs that we also wanna handle. So I implemented this here with regular element that uses the microtask queue and you can see that as the triangle updates in size we get some jank in the middle there and we wanna avoid that. So it's very simple to re-implement this just by changing the base class to lazy lit element and now you can see that we get a smooth animation even as we update the labels here. But next I mentioned we wanna have these high priority inputs. So this brings us to the idea of urgent updates. If you defer rendering, it's possible that you have situations where you wanna render sooner than you've scheduled yourself to be rendering. And so with these urgent updates, what we've done is we've created in lazy lit element, we don't just override the schedule update method, we add a new method on here called request urgent update and that's gonna be called and make your element render sooner. And it's a very simple implementation, I wanted to show it because it's a little bit interesting. So instead of waiting for a promise that resolves with set timeout, we still do that, but we also store, let me go back here. Maybe not. We restore the resolve function on the instance of the element when we schedule an update. And then we can go back and we can call that resolve function which will cause our promise to resolve earlier than it was scheduled to. So in essence, we're kind of jumping from the task queue over to the microtask queue and we're gonna render as soon as possible. Okay, so this is how you would use it. So we have a partial implementation of our dot element here and these are some event callbacks that might be called from on mouse over and on mouse out and they're simply gonna set the state that our rendering is based on and then they're gonna call request urgent update to kick us to the faster timing. And so once we do that, you can see that we have our smooth animation, our labels update and we get a fast hover over effect here by calling request urgent update. Okay, and let me talk real quick about scheduling. So in that demo there, I did a very simple thing. I said instead of using a microtask, we're gonna use a full task. And I actually didn't expect that to work as well as it did when I made the demo, but it did work very well. The browser ends up doing a very good job of kind of executing as many tasks as it can before it has to paint a frame. But it's pretty naive and it leaves off a lot of features that we would like like different priority queues, the ability to cancel work, the ability to coordinate long chains of tasks that are all related together. So that schedule update method is exactly where we would like to plug in to a native platform scheduler API like Shuby and Jason talked about earlier. So the important point is that with web components, we don't have a kind of overarching framework that can coordinate and schedule our components for us and we might get components from different vendors. So being able to plug into a global platform-vendored API for scheduling is gonna help us tremendously here. Okay, there we go. Let's move on to talking about managing async state. So so far we've talked about being asynchronous on a per component level. So yielding to the browser and letting it paint in between components. But sometimes we need to manage data that itself is asynchronous. And let HTML rendering is synchronous by nature. When you give the render function a template, it's gonna do all the work immediately to render that. So what do we do if we wanna render asynchronous data inside of a synchronous template? So we can look at how we handle data normally here and if we have a string and just kind of a plain reference to that string, it's pretty easy to use. We just use it in a template and we get the rendering that we wanted. And if we change this instead to load off the network, it turns out that let HTML handles promises already. And so what we'll get is a blank screen here and then when the promise resolves, we'll render hello world. So this is kind of nice. We get some behavior that we might expect right out of the box. But we might not wanna render a blank screen as our initial state. So this brings us to the idea of directives. And these are functions that are a little bit special and they're able to customize how templates are rendered by let HTML. And one of the more useful directives that let HTML ships with is called until. And what until does is it takes a promise and it will render the result of that promise when it resolves, but it will render a placeholder until that promise does resolve. So we can use that here and you see that in the template, we call the until directive with our promise and the loading placeholder and that's gonna show first and then when it resolves, we're gonna render our content there. So this example is a little bit too simple because it assumes that we have this promise available already that we wanna use. And a lot of times, instead we wanna run some task when we need to render and we might have some operation that's dependent on some instant state. So in this version of the example here, we have a file name property and we wanna fetch some data based on that file name. Now we might be tempted to call fetch inline with the template so that we'll fetch the correct file and then render it. And this does work, but it has a problem where every time we render this template, we're gonna call fetch and we might be rendering the template because some other properties change. And in this case, we're gonna flood the network with lots of fetch requests. And we also might show an alternating kind of loading and resolve state in our UI. But it's almost the mental model that we want, right? So what we really wanna do is we want to be able to run a task that's dependent on some data only when that data changes. So that brings us to the next experimental helper here that we call run async. And what run async does is it performs an async operation but only when the data it depends on changes. And it's actually a kind of directive factory. So the way it works is that you give it an async function that takes some data and produces a result and it returns to you a directive that you can use inside your lid HTML template. So if we wanna reproduce the previous example here using this fetch, we can just create a fetch content directive by passing run async a function that takes a file name and calls fetch for us. And when we go to use it, we can just use it inside of our template and we pass it the file name here and then we pass it another template that's gonna render when we have successfully resolved that promise. So this lets us get part of the way to our goal here. We can render some asynchronous data but it turns out that asynchronous data can be in a number of different states. For any async operation, you can be an initial state which means you haven't started it, you can be pending, it can have successfully completed or ended in failure. And so it really helps us if we model and think about all of these states explicitly so that we make sure we handle them. We can see that our directive actually takes templates for all of the different states that our UI can be in. So we have a success template, pending template, a initial state template and the error template. And to make this a little bit more realistic, I made a demo that searches the NPM package repository. And this is a basic kind of searches you type live search result demo and it has a simple UI, we just have a search box and a results panel down here. Okay, so we're gonna build this demo in two parts, hopefully. So first we're gonna define a search package's directive using run async. And so here's our initial starting point for this directive. Our async task function here is going to generate a URL for the NPM search service here and then get the results by fetching it. And then here we're gonna handle the response and just do a little bit of due diligence and make sure that we have a 200 response and return that, otherwise we throw the message we got back. And I wanted to make this task able to kind of trigger that initial state template. And the way we do that in async is that we throw, in run async, we throw an initial state error. So here I'm just gonna check to make sure we have a query we can execute and if not I'm gonna throw this error and run async is gonna render the initial state template. And then it turns out that the NPM registry is a little difficult to get it to trigger an error. Usually it just returns empty results. So to be able to show the error state template, I just do some pre-validation here of the query and make sure we don't start with the dot or underscore. And then finally to make this even more realistic, if you're doing a search as you type UI, you're gonna have a lot of requests that you initiate where you don't care about the results because you've typed in a different query by the time the result gets back. And so the Fetch API is able to take something called an abort signal so that we can cancel the requests. And so run async will generate an abort signal for you and then you get it in this options argument here and you can forward this on to the Fetch API. And so this is our entire search packages directive here built with run async. And so next we just need to use it. Here's a little snippet of the demo UI. We have an input element here which just simply displays the query and updates the query on input. And then down here we use the search packages directive. And so we use it by passing it the query and then we give it a success template. Here we just iterate over the results and display little cards. And then we give it the pending initial and error state templates here. And so when we go to use this demo, we see that we have the initial state template rendering, sorry that's small, it says enter a search term. When we type it turns into loading and then we get our results back. And if we were to go back and enter a query that starts with an invalid character, you're gonna see the error template there and that even updates as you type. And if you realize your mistake and go in and type in a new term, you're gonna get all the intermediate async state templates as you type. So that's the demo and now you really did see most of the implementation there so it was quite easy to do with that directive. And the key takeaway here is that we wanna explicitly model our asynchronous operation state. If we do that, we're more sure to take care of all the states that we can be in. And if we build a UI for each state, then we're gonna accurately let our users know what is going on with the application and they're gonna have a better user experience. Okay, so finally, once we have an application and a UI built up of all these asynchronous components, we might need to coordinate them. So if you have a lot of async children in your page, how do we ensure a consistent UI if you want to? Or how do we avoid a sea of spinners? And so I added to demonstrate the sea of spinners problem, I added to the demo a little feature here where when you search, the cards are gonna do their own query to bring up the disk tag of your MPM packages. And you can see there that we saw a lot of spinners on the page and this can be kind of a distracting UI so we wanna give developers an option to not have to deal with a sea of spinners. And the way we're gonna handle this is that we're gonna coordinate the components here with events. So what we're gonna do is we're gonna fire a promise carrying event and that promise is gonna resolve when some work is done. So an async child component creates a promise, fires this event and then resolves the promise. And so that's gonna look like this, A is gonna be our container up there and E and F are async children and they're gonna fire this pending state event that holds a promise. The container is gonna handle the event and wait for that promise and then the children when their work is done, they're gonna resolve the promise and finally, when all the promises have settled, we're gonna update the UI. So that brings us to our last experimental prototype here called pending container and pending container kind of takes care of all this plumbing for you. And it's a class mix in so you can apply this to a super class like lit element and this has two features too. We have a has pending children property so this indicates whether or not there's async work happening below you and when this property changes, it's gonna cause a re-render of the element and then we have an event listener that listens for the pending state event and then triggers the bookkeeping so that we know if we have any extra work pending below us and to use it, you can just apply this mix in to the super class here to lit element and once you do that, you get available the has pending children property that can use in your template and so now we're gonna add a spinner and this is a top level spinner to the UI that's triggered based on whether or not there's any pending children and so the run async helper is gonna fire these events for us and this container mix in is gonna capture them and so what we're going for here is a UI where we have a spinner and it happened again. There we go, okay. Might just be a faulty button here. So what we wanna add here is a spinner at the top of the UI that's gonna be going whenever there are pending search results coming back from the server or we have children that need to update. So now you see we get the spinner as we type. We don't get the spinner on the children but we can see the top level spinner is still going and then the results come in and the spinner stops and so that's the UI we were going for and it was pretty straightforward to build with these directives. So when you have an asynchronous UI there's a lot of different options that you have for how to handle this. You could try to block the UI while you have pending work. You could show the raw incremental updates. You could have individual spinners on your page or you could try to replace that all with top level placeholders and spinners. So what you wanna do kinda depends on the UX and the UI that you're trying to build but the key here is to provide the plumbing and the framework and the nice API so that you can build whatever you choose to build. And that went two slats for it. All right, well this is my wrap up. So we're very excited about some additional work that's gonna be done in this area. So Jason and Shuby talked about the native scheduler API which we're extremely excited about. Display locking is a new proposal where you're gonna be able to lock an entire portion of your screen so that you can update it incrementally and then flip it to the new version and Gray talked about virtual scroller which is gonna let us handle large amounts of data as well. And then on our end we're gonna be working on more libraries and examples of how to do things like lazy load components, background rendering and viewport based visibility rendering so that things only render when they show up on the screen. I have a few links here. These would probably be easier to get to from the video. And then I'm gonna be over in the ask Chrome area doing Q and A after this if you'd like to ask any questions. Okay, thank you.