 My name is Steve Vorval, and I work on the core Polymer library as an engineer. And today we're going to talk about some practical performance patterns that you can use while making your Polymer web application. And I need the clicker. There we go. So performance is really a measure of time. It's a time it takes for us to load and display content to the user. The time it takes from when our user clicks on a button for some action to occur. And we know that if this takes too long, the user gets frustrated, and they may bounce and leave our site. We don't want that. But exactly how much time is okay? How much time can we let these things take and still delight our users with good performance? So Google has some guidelines for this called Rail, and how many of you have heard this term before? Okay, a fair number. I encourage you to check out these tons of information available online about Rail. And today, actually, we're going to focus on the L in Rail, which stands for load. And the goal of the guidelines is to try to load and display interactive content to the user in just one second. So we know at least that gives us a goal to shoot for. But how will you measure this? How will you try to figure this out if your app is hitting this goal? There's a lot of ways, but one way that we really like on the Polymer team is this site called webpagetest.org. And it's really easy to use. You just input your URL. You can select a device and a browser. And a connection profile, like a mobile profile, it's really easy. The site churns for a little bit, doing some testing, and then you get a nice report of how long it takes. And it's going to tell you if you're hitting that guideline. So if we do that for Google.com, then do we hit this guideline? Well, it turns out if you do this test for Google on like an average phone, like an XS5, and average mobile 3G connection, then typically when you test this, it actually does hit the rail guideline, but not really with any room to spare. And as you may know from going to Google.com, it's not the most complicated looking website. So this pretty much gives us an indication, as you may probably already know as web developers, that this goal is pretty darn tough to hit. And it turns out sometimes that if the connection is flaky enough, a flaky 3G connection sometimes, for example, then you may not even get a response from the server within that one second time frame. So we may not even be able to do anything. We're doing nothing and we're still not hitting that goal. So this is tough. The guidelines are basically telling us this is what will please our users. So it's telling us that there's not a whole lot of room for us to do work on our own. And so we should really take this seriously and pay attention to performance and do whatever we can to minimize the impact of the things that we can control. So going back to this question of time and measuring performance by looking at time, what are those things that we can control? So first, there's obviously the things that we're downloading to the browser. This is the JavaScript HTML and CSS that we're all familiar with. And the quantity of that is going to be important contributor to the overall time that we're taking. And second, of course, there's rendering that content to the screen. And this is going to be basically the other main contributing factor that's going to lead to the overall time that our site is taking to load. So clearly, if we can reduce either the amount that we're downloading or the amount of time we're taking to render, then we're going to improve the performance of our site. So that sounds good. That gives us some really concrete things to look at. And first, what we'll go ahead and do is dive into this idea of how much we're downloading for the user and see what we can do to control this. So I apologize because I realize you've heard this term, like, in almost every talk. And I honestly didn't realize this would be the case. But we are fans of this idea of using the platform. And specifically, let's just take a quick look at what this does to the amount of content that we're downloading if we do the best we can to try to use the platform to help us. So first, if we use Web Components, this is going to help us minimize the amount of JavaScript framework code that we're downloading to the user. And in Taylor's talk, he mentioned that Polymer on Chrome, for example, where all the native Web Components features are implemented, is getting a lot smaller in version 2.0, where we don't have to load polyfills. And if we use Service Worker, which has been mentioned also a lot today, then we know that this, for downloading on the second and subsequent loads, we don't really have to worry as much about this question of downloading because we're going to have this reliable cache that's going to help us. And so it becomes much less of an issue in that case. And finally, you've also been hearing about the purple pattern. And again, this stands for push, render, use a service worker to pre-cache, and then lazy load. So again, it's push just the content that my user needs for the initial route that we're rendering, use a service worker to pre-cache the remaining content, and then lazy load that on demand as the user's interacting with the site. There's a lot of content here. And at Google I.O. this year, there was a great talk given that I highly recommend that you check out. We apparently like our Ps and Polymer. And there's a lot of information there about what the pattern means and sort of why we think it's good and what you can do to implement it. So also at Google I.O., we released the shop app. And just to be real clear, this is a demo app. You cannot actually buy things on this. And this has actually come up recently with users using it and trying to wondering where their shirts are. And this is really where we kind of, the crucible where we formed and tested out the purple pattern. And we were really happy with the result. By using this pattern, we were able to improve the performance of the shop app pretty dramatically using, again, web page test to test this. By multiple seconds on each of the routes for the site. And at that point, we were pretty happy. We thought we were onto something. We thought, okay, this is a good pattern. This is pretty straightforward and useful for people. And then a little later this year, the team that makes the Chrome UI, which is actually just web pages like you and I make, they came to us and they said that what they needed to do was rebuild this, these pages. They needed to use Google's material design. They were keen to use Polymer and we thought that was great. And then they said, well, the users of Chrome demand that these pages load in just a couple hundred milliseconds almost instantly. So they laughed at that rail one second guideline. And they noted to us that the resources that these pages need are actually installed with Chrome. So they don't have to worry about a network in downloading these resources. So they didn't have to worry about a huge component that we just talked about. So for them, instead, the issue of performance was really the other component that we mentioned, this rendering question. So for the rest of this talk, we're gonna really focus on the idea of rendering the content for our users to the screen. And what we can do to minimize the performance impact of that. So let's dive into that now. So again, if we sort of look at this concept of time, and now we're really just focused on the time to render, it's really a function of two things. First, we have the number of elements that we're using to display our content. And the cost of those elements, the average of how much each of those is costing us in going into that time. And we can see, looking at this equation, again, if we reduce either of those, it's gonna have a positive impact on decreasing the amount of time we take. So, how are we gonna do that? Well, it's not quite as simple as this, as going to the beach and just relaxing. But as the title of this talk says, we are gonna try to sort of use this mantra and do less and be lazy. This is really, if you take one thing away from this talk, it's this. Do less means making less elements, rendering what we need and less work. Being lazy means trying to do this efficiently and doing just the work we need to accomplish the task at hand, the rendering, and then with the way the user is interacting with the app. So, with that in mind, let's try to dive into some specific techniques that we can use to, in this case, we're gonna first focus on reducing the number of elements that we're using to render that critical content for the user. So, we'll look at a few techniques that we can use. And the first one of these is called incremental rendering. And the idea here is, again, just do absolutely what's necessary. And then sort of in seamlessly in the background, we'll let the rest of the rendering occur. And I'll explain this with an example. So, you're probably familiar with Polymer's DOM repeat element, renders a version of this template for each, in this case, element in the items array. And if that array has, say, a thousand items in it, then we're gonna get a thousand stampings of, in this case, this my item element before anything is rendered to the screen. So, I mean, if there's any, if the my item element has any complexity at all, this is very likely just gonna take too long. So, what do we do? Well, we actually recently added a feature to DOM repeat called initial count, which is going to do this incremental rendering for us by rendering this set amount, in this case, 10 items. And then letting the user see what's on the screen, and then seamlessly in the background doing the rest frame by frame, usually very quickly, and just filling in the rest. And this is a pretty good trade-off in terms of getting a good first experience and having the rest just kind of happen behind the scenes. And I'd like to mention also that in Polymer 2.0's version of this feature, this incremental count is implemented by default. So, you'll get this behavior without having to do anything. So, another way that you can accomplish something similar is to use IronList, which Eric mentioned. And this is even better performance than DOM repeat, because IronList only ever renders just a bit more elements than will fit on the screen. And then lazily, as the user interacts with the IronList and scrolls through it, those elements are reused and the model items that are appropriate to be shown at a given time are displayed. I would suggest using IronList when you have a fixed viewport height and the content of the list is mostly homogenous. Then it's gonna be your best bet. Okay, let's go ahead and look at the next feature that you can use to try to reduce the number of elements that you need to render. And that's conditional rendering, and we'll again explain that with an example. So, you're probably also familiar with Polymer's DOM if element, which is again a basic tool that you can use to accomplish conditional rendering. So, let's look at how I've used it here, specifically. Because this is actually a time when it's a good time to use DOM if. In this case, it's gonna render if a property called usually false is set to true. I specifically named it usually false because it means that in the common case, it's not gonna be true and we're not gonna render this content. So again, in that common case, we're gonna render less elements. And the element inside here, big view, is very likely to be kind of a bit of an expensive element. So it's a reasonable thing to hide behind this use of conditional rendering. And it's not always a good idea to use this kind of conditional rendering. Sometimes it can be a negative, and let's look at that. So here we've used DOM if and the property that we're conditionally rendering this content on is called usually true, which again means that in that common case, we're probably gonna render this content. So it's actually not helping us. And the content that we're rendering is just a div and it's really cheap. So in this case, the conditional rendering logic that we're using here is probably not even worth it, not paying for itself. And if the content is this simple, then I would recommend just showing and hiding it using CSS. So don't use DOM if here, but use DOM if when the condition is usually false and it's gonna help us in the common case. Okay, so one more feature that we'll look into for reducing the number of elements that we need to render is custom element upgrade. So there's a lot of potential content here, and I'm just gonna focus on the essential bits. Again, with an example. So here we have an element view template where we're showing this big footer element. And it's a footer, it's at the bottom, maybe it's big. So we've chosen in this case to not let it render its full content when we're displaying this initial view here. It's not essential. And it's convenient for us to put it in the DOM like this because it lets us put some fallback content, in this case we chose to say loading. And we can use CSS to style the element, it's just a regular element like anything else. It gives us a good way to style it. And then based on some condition being met, we're gonna call this load footer method in this case. And it's gonna use Polymer's import href, which is a imperative way to create an HTML import and load it to load the definition for the big footer element. And that will seamlessly go ahead and upgrade it when that import loads. And this is again a good way to be lazy and do this work sort of a little bit, it's a little bit less important than for that initial render. And therefore, we can avoid all the, in this case loading the content that we need to load for the big footer, which will help reduce download. But also importantly, not rendering the shadow element of the big footer element that's less important for our initial render. Okay, so to recap, to reduce the number of elements, we've used these techniques and that should be pretty beneficial. So again, to review, all of these techniques are, follow this do less be lazy idea. Okay, so now let's go back to our equation here. We have time to render, number of elements. We've talked about techniques to reduce that. Now let's look at this cost, the cost of these elements. So we'll look at some techniques to help us there. So before we do that though, let's pause for a second. Because it's really important to realize that it's not practical or smart to try to reduce the cost of every single element that you make. It's okay if some of the big view elements that we make just want of or a couple of take a little bit of time to create. The elements that we really want to focus on, the elements that really we don't expect to be taking this much time. And especially the elements that we are using a lot on the page. And we sometimes call these high frequency elements. So high frequency elements, expensive elements are really the ones to focus on. So also important, how are we going to figure out which of the elements meet these requirements? We need to use tools. And in addition to the Chrome DevTools timeline and the profiler, which I hope you're all using, we can use another tool that the Palmer team has created called Poly Dev. And this is another way to help dive into specific element types in your app that are costly and help you determine how many of them you're making and how much they cost. So that'll help us determine which type of element to focus on. So another tool that we've created called Polyperf is another example of the thing that Eric talked about, which is a sort of metrics thing. There's actually almost everyone in our team has a different tool for doing this. And if you want to make your own, that's fine too. This is just one that we found useful. And this is a tool that will help us benchmark individual elements and compare sort of different changes that we can make. And it's doing some work here to try to render the elements a bunch of them and report times back to us. OK, so as a final thing that we'll do in this talk, let's go ahead and sort of do a case study of trying to reduce the cost of an element. And here we've taken a ratings element, which is just something I sort of made up for this. And it's an element that you can use to maybe show a movie rating on your site. And you've decided to implement, you can click down on it and select the rating. And it's a good candidate to try to reduce the cost for because it's very likely to be a high frequency element used in a bunch of places. We might use it in a list, for example. So let's kind of dive in and see if we can find some ways to reduce the cost of this element. So let's look at how it's made. So first we have its template. And it's actually pretty simple. We actually made some good decisions to start. We realized that we could use a little star emoji rather than having to download an SVG or image for the star. We also used Polymer's strip white space feature, which is a convenient way to knock out the text nodes in the template. They're really convenient for readability, but they do have a slight performance impact. And in most cases you don't need them. So in an element like this that we're really trying to squeeze all the fat out of, it's pretty reasonable to do that. So the next slide is going to be most of the code for the element. And I'm pausing now because don't freak out. It looks like a lot here, but this is actually almost all of this code. And we're going to go through it step by step to just look at what's happening. So first we have some attributes. And again, I'm showing some of the Polymer 1.0 syntax here that's hopefully a little more familiar to people. So we want to make the element focusable and give it a role, an aria role, so that it's accessible, which seems straightforward. I do want to have a little maya culpa here. This is not everything we need to do to make the element accessible. The other bits actually don't have a significant performance impact, so I admitted them. But it's not complete. We have some event listeners. In this case, we have a key down listener, which is going to help us with the arrow keys. The left and right arrow keys are going to advance and reduce the rating. And the down handler here is saying that we're going to have some code here that will set the rating based on the star that the user clicked on. We decided to expose a public property called rating. It's pretty straightforward. And we decided that it should reflect to an attribute. And it should send an event when the rating is set. And we have an observer here. And the observer here is accomplishing the rendering of the rating. In this case, don't worry about the code. But it's basically looping over those star elements and setting a CSS class on them. It seems straightforward. And we have a value property, which is setting the default for the rating to zero. So finally, we have a paper ripple. You saw in the little video we had a little ripple effect. I didn't do the work to make it circular. It's a little bit more work, but it probably looked better. And we're creating this paper ripple. And then in the down handler, we're moving it to the right spot so it'll ripple on the right star. And that's great. We get a little material design effect. We don't have to implement it ourselves. We can use that paper ripple element to help us. So straightforward, pretty simple element. What is it? How does it perform? So we can use polyperf. And we can see that when we do that, I've compared it here to the native input element. And I'm using the tool polyperf here to, it's actually rendering 250 of these in each test. So in absolute terms, the cost of the ratings element is pretty cheap. It's like a fraction of a millisecond, about half a millisecond, which is not bad. But I chose to compare it to the native input because it seems like it shouldn't be that much more expensive than that. I mean, it's a straightforward element. We want to make it as fast as we can. So it's actually a bit slower, six and a half times slower than input. So it's not quite where we want it to be, maybe. So again, now we're going to dive in and take a look and try to go sort of step by step to try to see ways that we can reduce the cost of this element. So we'll use this technique. The first thing that we're going to try to do is look at our use of composition. And in this high frequency element, we're going to be a little bit careful about it. In general, composition is great, but when you're really trying to squeeze the fat out of an element, then we want to scrutinize it carefully. And you may have noticed on the previous slide, I use this element called shadow card, which is really just there to give the outline border of the element a drop shadow. And in this case, it's probably a little bit heavy weight to accomplish that end, probably not worth it. So let's try to avoid that. And in this case, to do this in CSS is actually pretty straightforward. So let's just use the platform more directly and use that CSS. And then we'll look at what impact this has on the overall rendering performance. So we can see we got a nice little improvement. And again, we kind of overused an element there where we really didn't need to let in the platform just directly via CSS to do that heavy lifting was a nice little improvement. So the next technique we can look at is reducing the work that we're doing in ready and attached. And specifically, this is important because these lifecycle methods are called before our initial render of the element. So remember this paper ripple that we created? We made it in ready. But you remember that I said it's actually only used in the down handler. So it kind of makes sense for us to do this work lazily and move the creation of the ripple element to the down handler like this. The first time that the user presses down on the ripple, or sorry, on the rating star will make the ripple element and then use it. And then therefore, we're doing the work lazily. So let's look at what impact that has. That's pretty significant. We got a nice bump here. This is not totally surprising given that paper ripple is doing a pretty fancy thing. It's doing some complex work. And by creating that element lazily, we save ourselves a good chunk of work for that initial render. So we're getting there. And not quite there yet, but we're getting there. And the next technique we'll look at is using CSS more for dynamism. We already did for the box shoutout. Now let's look at it for other things. So if you recall, we had this observer when the rating property changed. And we are using CSS, but indirectly we're using JavaScript to imperatively set some classes on the element. And as it turns out, we actually don't need to do this at all. And we can use this fancy CSS instead. In this case, we're choosing to use the fact that we reflected the rating attribute to the host and tell CSS user selector that knows about that. And then use this nth of type selector to say, OK, well, we're going to conditionally style the star, the appropriate star, according to that rating. And this was just enough to get rid of that observer completely, letting the platform do the heavy lifting. So let's see what impact that has. So that's a nice improvement too. Using CSS for dynamism as much as we can, writing less code, seems good. Let's keep going. OK, so you recall I said that we gave the rating property a default value of 0. And as it turns out, to accomplish this render, we don't need that, especially since we did it for UCSS. Based on there being no attribute set, all the stars will just be black, which is good for our initial render. So we don't need this. This can avoid reflecting that initial property to an attribute and avoid sending the event. And this is really good for our initial render. Let's see what impact that has. So not huge, but we're getting there step by step. So one last change that we'll look at is looking if there's any other work that we can defer until after the initial render. And in this case, there's these attributes and these event listeners. And again, those are not critical to our initial render of this element. And again, in this case where we're really trying to squeeze all the fat out, we can avoid using this. And instead, use a little helper that Polymer has called afternext render, which is going to do the work after the render. And set these tabindex and the role and add the event listeners, imperatively then, which is going to, again, defer this work until after render and get us our initial render as fast as we can. Let's see what that does. OK, so that was pretty significant and got us pretty much almost all the way to our goal of trying to sort of at least benchmark ourselves against the native input. So we got a number of big improvements there. And again, here's all the techniques that we used. And you don't have to remember each one because really, sorry, taking together, of course, we looked at this and we looked at some ways to reduce the number of elements and the ways to reduce the cost of the elements. And here's why I'm getting it, that you don't have to remember any of these specific things. You can, of course, review for that. But to keep in mind, if you remember one thing, it's just that steal this and be lazy because all of these things that we just talked about really express this main idea. So here are the things that I talked about in the talk. There's a link for Rail, the link to that video for Purple, the download for Polydeb, and that's available on the Chrome Web Store. This is the branch of the Polyperf repo on GitHub, which has that ratings element built in. You can actually run those tests yourself and check out, modify whatever you want and look into it. And that's it for me. My Polymon is Octorvel. And apparently it likes to spout wisdom for long periods of time, so I want to warn you about that. But that's everything. So thanks and have a good rest of the day.