>>Steve Souders: Okay.
Is that my cue to go?
Okay.
We're having a current discussion about letting people come in and sit up front, so I hope
we can do that.
I'm really excited to see everyone that showed up, but I have a cold shower announcement
to make.
I'm not giving anything away.
So although that's not entirely true.
I'm giving away information and knowledge, but nothing that physically you can take home
and give to your kids if that's what they're expecting.
So I'm going to talk about HTML5 from a performance perspective, but first I'm going to start
off and give a little background on my work in working on Web performance and kind of
the motivation.
I think probably a lot of people -- how many people here build Web sites?
Yeah, okay, great.
So I think there's something in the DNA of engineers in general, and especially programmers,
to be efficient and optimize.
I think as developers we all like our code -- we feel proud if people -- if we can say
about our code that it's really fast and efficient.
And so at the beginning I'm going to talk about how we can try to work to instill that
interest and buy-in for performance across other parts of the organization outside of
engineering.
So there will be a little preamble on that and then we'll dive into the HTML5 stuff.
I just want to mention the slides are up on my Web site, stevesouders.com.
If you go there there's a link to it.
You can check that out.
Okay.
So let's get started -- oh, the other thing I want to mention is really more than what
I say and more than the words on the slides, I really want people to pay attention to the
photos in the background of the slides.
[ Laughter ] >>Steve Souders: Come on, we're going to -- loosen
up a little bit.
Let's go.
I mean, like the story of my life, like I take slow things and make them fast, like
is that very appropriate or what?
I need more feedback.
[ Applause ] >>Steve Souders: Yeah, okay, there we go.
I worked at Yahoo for a long time, eight years.
I was going to be there one year and I was there eight years.
And about four and a half years ago I joined Google, which was really my goal when I first
started on Web performance because I knew the people at Google really cared about making
things fast, and it's true.
So I've been there four and a half years.
I do mostly open source stuff, so I did -- I created YSlow, Cuzillion, Sprite Me, Hammerhead,
Browserscope.
Lindsey Simon now runs that project, very successful project.
Jdrop, which is a great concept, but not such a successful project, but you should check
it out.
HTTP Archive, another one I don't have time to talk about today, but check it out, HTTParchive.org.
I wrote "High Performance Web sites," "Even Faster Web sites."
I taught at Stanford based on the books and I run the velocity conference.
Oh, I have to update.
We just had it this week in fact.
I just finished that on Wednesday.
So I've been doing this performance stuff for quite a listening time now, seven years,
I think, but when I started back in 2004 I kind of felt like the lone voice in the woods.
So really I'm sure there were people that were working on it back then, but when I searched
for information about making Web sites faster, I really didn't find very much.
There was a great blog post from David Hyatt that actually really opened my eyes to where
I should look for making Web sites faster.
I should mention that when I talk about performance, I mean that from the end user's perspective.
My goal when I started this in 2004 was to make the user experience fast.
Now, there's another aspect of performance which I think of more as efficiency or scalability
on back end servers.
How can we handle 10X the current number of users with the same hardware?
Those kinds of efficiency optimizations are also performance, but when I say performance,
I really mean speed, speed of the user experience.
So when I first started working on this there really wasn't that much information out there
and I would try to go -- I started documenting things, writing books, blogging, trying to
go to other teams and convince them to focus on performance.
And it's kind of like QA or writing unit tests.
Like try to sell unit tests -- time to build unit tests to someone from marketing or sales.
That's kind of hard to do, because it's hard to visually see the benefit of that.
So at the beginning it was kind of the same thing with talking about make the Web site
faster.
Yeah, we need like a couple of people to work for at least six months.
And you won't see anything different on the site, it will just feel faster.
And believe me, that's really critical.
And they're like no, really we want you to add more flash.
[Laughter].
>>Steve Souders: And so fast forward to 2010, future of Web apps.
We have Fred Wilson.
How many people know Fred Wilson?
Like one of the most prolific bloggers.
He's the number one VC out of New York City, out of Union Square, very techy guy.
But really his business is investment, funding startup companies.
Here he is speaking at a tech conference about his 10 golden principles of successful Web
apps.
What's number one?
Speed.
He says, First and foremost we believe that speed is more than a feature, speed is the
most important feature.
And he goes on to talk about with their portfolio companies they track all of the company's
performance, speed, page load time for real users.
And that in their experience the data shows that when the speed drops off, the success
of the business drops off.
And that's why they do this for all the portfolio companies that they work with.
And so I think that's to me like Web performance has arrived.
We have a VC talking at a tech conference about speed, like this was beautiful to me.
I start almost every slide deck with this slide.
And actually, a partner of Fred's spoke at the Velocity conference this week.
And in addition -- if that's not enough to have the number one VC out of New York City
talking about performance, I'm going to run through a bunch of case studies here that
correlate performance speed to the success of the business.
So here's -- about two years ago Bing and Google Search got up on stage at the same
time and talked about experiments they had run.
Bing introduced intentionally a delay in serving search results.
They took it up to two seconds.
At a two-second delay they saw all their goodness metrics drop off.
Most significantly revenue per user dropped off four percent.
And of course, these companies are doing this on a very small sample size.
So Google took this up to 400 milliseconds at the max.
Didn't see that much dropoff in searches per user, although at Google scale that's a fairly
significant dropoff.
The thing that was really interesting about this study was after they removed the delay,
they kept that user group segmented and tracked their usage.
And it took I think six weeks for the usage, the searches per day, and other goodness metrics,
to resume where they were before the experiment started.
So the user's awareness of what the experience is like is something that gets ingrained and
lives with them and it takes a long time to build that and to recover from delays.
So it's important to stay on top of keeping your Web site fast.
And Yahoo ran a similar study.
And for full page traffic, that means traffic where the onload event actually fires, a 400-millisecond
delay saw a five to nine percent dropoff in traffic.
Here Mozilla -- this is about a year old.
Mozilla, when you want to upgrade to Firefox and you're in Internet Explorer, you get the
IE landing page, and they made that IE Firefox landing page 2.2 seconds faster, and they
saw a 15% lift in Firefox downloads.
So for them that's their business metric, being a nonprofit.
And this was a seminal study from Velocity a few years ago.
Shopzilla did a tremendous performance effort, taking their site from seven seconds to about
three seconds, and they saw conversion rate go up seven to 12 percent depending on the
country.
This is very significant.
They saw the unique users from search engine marketing more than double.
And this was the first study that showed another benefit in addition to the business metrics
is operating costs going down.
So here we have the number of servers needed to run the Web site after this optimization
dropped.
And that kind of makes sense because like one of the optimizations is connecting scripts
together, so instead of making seven requests to my server, I'm only making one.
Turn on Gzip so the amount of time it takes for the response to get off the server box
is lowered and so the server can handle a higher QPS.
And then following that a good friend of mine, Bill Scott, when he was at Netflix, they had
-- they didn't have Gzip turned on for some reason.
I can go into it after if people want to ask.
And he turned it on one day and the [Indiscernible] said the Web site is down, all we're serving
is the error page.
And he said why do you think that?
And they said the traffic in our data server has dropped in half.
He said, Nope, we're serving everything, it's just that we turned on Gzip.
So this is probably six figures a month in a data center that they saved.
Pretty significant.
Here's another example, Edmunds.com turned on -- added an expires header so that their
resources through their CDN could be cached and they saw their CDN traffic drop by a third.
So again, this is a six-figure maybe high five-figure savings per month from CDN costs.
And then not that recently anymore, this was about a year and a half ago, Google announced
that speed or latency was going to be taken into consideration for page rank.
And that was caveated, it's one of two hundred signals, it only effects about one percent
of search results, but still it's a consideration and page rank is really important.
All of these things about a year, year and a half ago I saw coming together and so I
coined a new catch phrase for this emerging industry called WPO.
It stands for Web Performance Optimization.
And actually as I mentioned, I keep mentioning, we just had Velocity this week, there were
a number.
Sequoia, Battery Ventures, Excel, Union Square were all there.
This industry is really growing up.
There's a number of startups in this Web performance space now.
And the elevator pitch is it drives traffic to your site.
We see that with search engine marketing, with page rank.
It improves the user experience.
You would think that making Web sites faster the user would get in and out more quickly,
and it's just the opposite.
All of these studies show that page views per session, session length all increase because
the users are having a better experience.
It increases revenue.
We saw stats on that with conversions, downloads, and it reduces operating costs.
So this all sounds pretty good, right?
Web PO is really taking off.
All right, that's the preamble.
How many people here think fast Web sites are good?
All right.
So hopefully if you're having trouble selling that -- if this is stuff that you want to
work on and you're having trouble selling that back home, you can take some of these
case studies and show people back home that this is a good investment.
You'll actually get a positive ROI.
And maybe these will give a little guidance on what you can track on the business side
to actually correlate performance improvements with the goals of the business.
All right.
So let's transition into the meat of the topic.
I don't want to debate about what HTML5 is.
There's the spec.
I also mean CSS3.
It's the new stuff.
So I'm going to highlight a few things around HTML5 and CSS3 that I think are really important
to pay attention to from a performance perspective.
So the first is if you want to optimize something you need to be able to measure it.
And right now what we'd really like to measure is the user's perception of speed.
Currently there's no JavaScript handler for brain activity.
So what we've been using as an industry -- as a proxy for that is the window onload event.
Now, the problem with that is, for example, if I do a Google search and I click on a search
result that takes me to Whole Foods, and I want to measure -- from Whole Foods' perspective,
they want to know how long it took for the user to click that link to when Whole Foods
was ready.
And the problem is tracking the start time.
How do you track the time that the user started by clicking on that link?
Because that's the user's perception time.
And what you can do is at the top of the Whole Foods page you can put a script lock that
takes a time measurement, but that totally ignores the time it takes for the request
to go up to the Whole Foods server, for it to stitch together all of the content and
send that back down to the browser.
So about two years ago Google and Microsoft formed this Web performance working group
as part of the W3C, and the first task was to create the Web timing spec, which is actually
three specs, navigation timing, user timing, resource timing.
How many people here use navigation timing to measure Web sites?
Good.
It's not good that there were so few hands up.
It's good because I'm going to talk about it a little bit.
So those of three and I'm going to talk about each one in a little bit more detail.
They're also working on a few other specs, page visibility I'll touch on quickly.
Script-base animations I'm not going to spend too much time on, but people are doing a lot
of animation with JavaScript and they're working on making that better.
And efficient script yielding, since the browsers are single threaded, if you have long running
JavaScript it can really degrade the user experience.
So what can scripts do to mitigate that.
But let me talk about the timing specs.
So navigation timing actually is out.
The spec is done and it's available today.
If you look at window.performance, there's this timing object.
And you can do things like from the timing object you can get the navigation start and
the load event end, take the difference.
And the nice thing is that the Web timing spec gives us two main things.
This is the first one.
This is the time at which the -- the epic time at which the user clicked on that link
on Google.
So now the user can -- the Web site owner can get the full time from when the click
happened to when the onload event or whatever event you wanted to.
And in fact if you put a little time stamp at the top of the page you can break that
into what I call the back end time, the time from the click to when the first byte arrived
and the time from the first byte to when the full page loaded.
And there's a bunch of other timings in there.
You can get DNS time and connection time.
There are a bunch of time values that you can get in there.
So this has been out -- the spec was finished probably about six months ago, maybe a little
longer.
And I think IE 9 -- no, I think Chrome was the first to implement it.
But it's in IE 9 and up, Firefox 7 and up.
They had some bugs in the Firefox 7 in the early days, but those are all fixed now.
It's on Android.
And I heard a month ago it's on Blackberry, but I haven't tested that.
And here's a good URL from Tony Gentilcore that kind of explains how you could use it
and some examples of getting different time values.
So one thing that's really cool is Google is taking -- for page rank is taking time
into consideration, but when they announce that -- I'm really proud of the work from
the make the Web faster team at Google, where it wasn't like okay, we're going to hold you
responsible for it, good luck.
We also rolled out several tools.
In Webmaster tools you can go in there and you can see how your site compares its speed,
compares to the rest of the industry.
And really the folks who were going to get penalized from a page rank perspective are
going to be in the lower 10%, maybe even lower than that.
So maybe you're not awesome, but if you're in the top 50% you probably don't have too
much to worry about there.
So that's a little help, but the other thing that's nice to get more granularity, if you
use Google analytics, we added this time measurement capability in Google Analytics.
I think we call it site speed -- yeah, site speed.
Yeah, this screen dump is a little old.
I think the UI is a little difference now.
But the nice thing is when we first launched it you had to add a little bit more to your
Google Analytics snippet, and then about three or four months ago we turned it on for everyone.
So even if you had no awareness of the site speed, time measurement capability, you've
been gathering data for about five months now, four or five months.
So you could go to Google Analytics and go and find this site speed tab and you could
get charts, and it's the usual Google Analytics slice and dice capabilities by browser, by
geographic region, by page, and you can see what your performance is.
This is my Web site, so I don't know what was going on there, but that was awhile ago.
See, now it's fast.
Well, in November it was fast.
Thank you for that.
I appreciate that.
[ Laughter ] >>Steve Souders: Oh, I think I probably -- now
it's on by default.
Oh, it's only in browsers that support nav timing, so we really need mobile browsers
to start supporting this more.
Oh, it's sampled.
So by default it's a one percent sampling rate.
If you have a huge Web site, like one percent is probably fine.
And the guys have done a really smart thing.
Like they don't start it at midnight and if you're a huge Web site you've used your one
percent by 12:15.
They, like, dole it out throughout the day.
But if you're a smaller Web site, you can change it with some Google Analytics commands
to cover 100% of your Web site, but it's limited, I think, to 10,000 measurements a day.
But again, those will be sampled throughout the day, so you won't get biases based on
peak time and stuff like that.
And then I'm just going to talk really quick about the other two parts of the timing spec.
There's resource timing.
And this is -- there's drafts of this available, but this hasn't been nailed down.
I don't think there's any browser that supports it yet because the draft is -- the spec is
still being defined.
But this -- if you think about it, navigation timing is basically this same information,
but it's at the page level.
It's really high.
And what we're doing with resource timing is we're bringing that down to every HTTP
request in the page.
So for every HTTP request in the page you can get DNS lookup time, connection time,
total time for that to come back.
This is going to be a great mechanism for if you're using a CDN to track how your CDN
-- or maybe you're testing out multiple CDN's, to see how their performance is going.
It does have to worry about security safeguards.
So you could have some kind of hack where, you know, on my Web site I have the logo from
some nefarious Web site.
And when you land on my Web site I can actually see what the DNS time is.
And if the DNS time is zero, I know that you've been to this other Web site.
So there are some security safeguards with HTTP headers.
Web sites can allow or not allow cross-domain tracking of resource timing.
And then there's also user timing, which is really important for people building Web2O
apps, AJAXy stuff.
Something like Gmail that is open for several hours, there's no concept of a page load time.
There's only one of those when you start it up.
So this is, if you're doing HXE stuff like compose, this will give you commands that
you can use to say the user is about to do a compose operation, let me -- let me mark
a start time and then when the compose is all done, you can mark an end time, you can
give it a label, and so it lets you define and track any timing episodes that you care
about in the Web apps that you are building.
So it basically is like nav timing but it's much more flexible and lets you define the
start and stop times whenever you want in your code.
The other one that I mentioned that they are working on is page visibility.
This one is important from a performance perspective.
Mostly from a -- from an altruistic perspective, but it could also affect, you know, what you
are doing on your Web site.
And so basically what the spec let's you do is detect when your page is visible.
So like one thing I do in the morning when I come in, since I can't stand to wait for
Web sites to load, is I have this script and I -- you know, I boot up my machine, I load
the script, it loads my 30 Web sites that I read every morning and then I go get breakfast
and when I come back, all of the pages are loaded and I can just go through all of the
tabs.
But only the top tab is visible.
And inevitably when I come back, if I left my sound on, my office manager, you know,
giving me a dirty look, because there's some hidden tab that's playing video.
And the sound -- or maybe multiple tabs that are playing video and the sound is just annoying
and it's like really?
Like you started the video, even though like the tab is not even visible?
Like why did you do that?
And the page visibility API introduces a way to detect whether or not the tab of the window
is visible.
And so this is also really important, like, if you are tracking metrics, like page impressions.
If the user opened the tab but they're never going to go to it, but you counted it as an
impression, that's a miscount.
Same thing with ads.
Again, the example of video.
You might be doing something like showing them, you know, stock updates or the latest
messages from friends or you might be rotating through a carousel of photos and they're not
looking at it.
So not only are you kind of -- like you might rotate through a carousel of photos that started
with their favorite photo, but by the time they opened the tab they are down to their
5757th favorite photo and you have kind of ruined the experience for yourself.
So you could use it there.
Um, the other thing that you can do is -- this API can be used for pre-fetching resources.
So the Web site owner can decide and -- the Web site owner can decide if they want to
pre-fetch resources maybe for the next page and also if the page should be prerendered.
This is something that Chrome does.
So Chrome can actually prerender a page in the background.
But one of the problems with doing that is, again, if there are ad impression counts or
page impression counts that are firing, and the page is being rendered in the background,
and the user actually never sees it, that's a miscount.
So the page visibility API gives people controlling those metrics the ability to only fire the
metrics when it makes sense.
And I think this is only in Chrome right now.
But what it looks like is you can say WebKit hidden is the property, you can look at to
see whether or not the tab is hidden and this is an event handler you can attach to to detect
when the page does become visible.
So we had script defer in IE for years, but now with HTML5 the async and defer attributes
are officially supported across almost every browser out there.
I'm not going to go into it here but in fact I've talked for years and written extensively
about the impact that scripts have on the user experience.
So I mentioned earlier how the UI thread, you know, the UI is single threaded, the browser
is single threaded, so if you have JavaScript, for example, that takes three seconds to execute,
the user is clicking in the browser and they are trying to scroll the window and nothing
is happening because the JavaScript is blocking any of that interaction.
And so -- so that also happens when the script is being downloaded.
So if you have a 500 k JavaScript payload and the user has a slow connection, again,
it can take seconds for that to download.
While that's downloading, the UI could be blocked.
Unless you can do your script loading asynchronously.
So if you just do scriptsource equals main.js it's going to stop the HTML parser from parsing
past that script tag and it's also going to block rendering.
No browser in the world will render anything below a script tag until that script is downloaded
and parsed and executed.
But you can use the async attribute which tells the browser to start the download but
to go ahead and continue parsing the HTML and rendering the DOM elements in the page.
So it gives the user feedback.
It's a better user experience.
The user can see the page rendering, especially because a lot of times we put scripts in the
heads of our pages, which means the entire body is blocked from rendering until all of
those scripts are downloaded, parsed and executed.
And so this tells the browser, download it in the background, continue parsing; and as
soon as the script arrives, parse and execute it.
So one -- two tricky things about this is you can't have any document.write in this
JavaScript code because parser is already past that point.
You are going to get very bad and varied results across browsers if you do document.write in
an async script.
The other challenge with async is suppose that I have three scripts, A, B, C, C depends
on B, B depends on A. But A is probably like jQuery, so might be my biggest script.
C might be really tiny, so if I load all of these async, which is the one that's going
to come back first?
C. If I loaded async, it's going to be parsed and executed as soon as it comes back and
it's going to get undefined symbol errors because B might not be back and A might not
be back.
You can't just willy-nilly add an async attribute to all of your script tags.
But what you can do is you can use defer.
If it's JavaScript that isn't critical for rendering content to the page, and doesn't
have document.write can add the defer attribute.
It's pretty similar.
It says download it in the background, let the parser continue parsing and rendering
DOM elements.
After the entire page is done, parse and execute these deferred scripts and do it in the order
that they were listed in the page.
And so if you have those interdependencies across scripts, defer is a good fallback.
But -- but this still doesn't give all of the control that I think is really needed
to build a good user experience for -- for Web apps, especially on mobile.
For example, one thing that I would like to do is I would like to download maybe a big
script, 100 k, 300 k, 500 k, but not parse and execute it.
It might be a script for something like popping up a div to compose a message or address book
stuff that is only needed if the user starts typing an email message.
But if I download that, as soon as it hits the browser, the parse and execute is going
to happen and it's going to lock up the UI.
So I really want to get this JavaScript down to the device, get it in cache, but parse
and execute it, depending on what the user does.
The other thing that I would like to have is a control over when the download happens.
Right now the spec doesn't say when browser should download the script.
But if I've said defer, if I've said async, certainly if I've said defer, I would like
you to do this download, after everything more important is already done, because there's
a limited number of TCP connections that the browser will make, and if you download scripts
or multiple scripts, then things like the background image of the page, the logo at
the top of the page, might actually be pushed out because you are already using the six
TCP connections that most browsers allocate to a domain.
So we don't have control over those in markup, but there are techniques that you can use
to get that behavior.
So this is one that Gmail wrote about quite a while ago.
Gmail mobile team.
And it's a hack.
I think it's a beautiful hack.
So what they did was in the page, they have -- you know, maybe 300 k of JavaScript.
I'm just making these numbers up.
I don't know how much JavaScript Gmail has.
It's probably more than that.
But they have a lot of JavaScript in here and they just wrap it in -- in comment delimiters.
So what happens is this will get downloaded to the browser, it will be cached, it's already
resident.
But it's not parsed and executed.
So -- so let's say this is compose a new message JavaScript.
It pops up in div, it formats everything, it does error detection and things like that.
So we don't really need this JavaScript to block the UI thread for parse and execution
until the user actually clicks on the compose button, which they may never do during this
session.
So what we do is we download the code because we want it on the device.
When they click compose, especially on a phone, we don't want to wait to download 300 k of
JavaScript, we don't want to make the user wait.
So what we do is we download it, you can even download it in the background.
It's not going to block the UI thread when it arrives.
Now the user clicks compose, you have all of the JavaScript on the client and now you
just find the DOM element for the script tag, remove the comment delimiters and eval the
code.
A lot of people say eval is evil.
Doug Crawford is here today, I saw him downstairs, he'll tell you that.
Certainly eval is evil from a security perspective.
If you are eval'ing code that you didn't generate, that can produce really bad things.
You wouldn't want to do this with third party widgets and ads, et cetera.
So this is code that you control, that you generated.
So from a security perspective, it's okay and the actual performance of eval is less
than 10% worse than just a script block.
So from a performance perspective, it's actually down like around one or two percent.
From a performance perspective, it's fine.
So you control the code, performance-wise it's good.
So this is a -- this is a really nice hack.
And it's perfect for pre-fetching JavaScript that you might need but you are not sure.
It's possible that you will never need it.
So don't block the UI thread, especially for large amounts of JavaScript.
You know, this -- might require a fair amount of rewriting on your Web site.
So I wrote something called ControlJS, that's open source, you can get it off my Web site.
Several big companies -- I was just at this conference, and I found that -- including
Wal-Mart, I found several big companies that were using this that I was really surprised
at because I don't do a lot of testing.
[ Laughter ] >>Steve Souders: I trust that they've done
that.
And actually, who else -- Washington Post is using it.
And I asked them to contribute back the robustness changes they had to add.
And so the thing that I like about this technique is that it's all done in markup.
So we can just change -- instead of script source, having type text script, we would
say text CJS, and instead of a source we have a data control.js source, so this means that
the browser will basically just ignore this and you can also do it with inline scripts
just by changing the type.
Then you load control.js.
What it does is it crawls the DOM, and it finds these script nodes and it does the right
thing.
It downloads it asynchronously, it does it in the background.
Again, you would only do this with scripts that aren't critical for generating the initial
user experience and scripts that do not have any document.write.
But I think it's a little easier to get on top of.
You can even add this execute false, which says downloaded but don't parse and execute
it.
And then later when the user, for example, clicks on the compose button, you can say
control.js execute script.
So that's kind of a nice alternative.
The other thing I like about it, how many people here have played with -- with JavaScript
loader, script loaders, lab js or YUI lowered.
Some people -- the thing that I find ironic about all of the other alternatives out there
is their goal is to help you load JavaScript asynchronously.
They do that with a helper script, but you have to load their helper script synchronously.
[ Laughter ] >>Steve Souders: Anyone else think that's
weird?
Like, you know, synchronous loaded scripts are bad.
So you load our scripts synchronously and we will help you avoid that problem.
[ Laughter ] >>Steve Souders: Like -- so from the beginning,
one of the requirements of ControlJS was that you could load it asynchronously.
So you would use the Google Analytics, async loading pattern and load the script anywhere
you want in a page and everything will still work.
So JavaScript is a really, really big problem.
I'm -- make sure that you look at how it's impacting your Web site and if possible adopt
some of these asynchronous loading techniques.
Okay.
Shifting gears, I wanted to talk about app cache, which is good for offline apps and
also for longer caching.
So again, the importance of the background photo.
You are in the desert.
You typically don't have a good connection.
So having the offline apps is really important.
[ Laughter ] >>Steve Souders: There we go, the groan.
So building offline apps is really cool.
I think Google docs just announced that this week or last week.
It really helps with the user experience when you have a bad connection, you are flying,
whatever.
But also people are using it from a performance perspective for better caching.
So this is a study that I did five or six years ago with (saying name) when we were
at Yahoo, it's been a long time, but I've talked to people at other big Web companies
who have run the same experiment and they basically get the same results.
So I encourage you to run it on your Web site.
Basically we put a hidden pixel in every page, we tracked how often people made a request
with or without an if-modified-since header.
If they send the if-modified-since request, it means they have it in the cache.
If they don't, it means they don't have it in the cache.
So we can track how many people coming in, how many page views are done with a full cache,
a prime cache.
Our resources are in their cache or with an empty cache, our resources are not in their
cache.
I talk about in my best practices setting a far futures expires header.
Turns out even if you do that, browsers aren't going to keep things around for that long
or for whatever reason, users are going to come in and they're not going to have everything
in cache that you might expect.
So what we see here is that for page views, if you look at it from the page views perspective,
about 20% of page views on any given day are done with a -- with an empty cache.
Right?
My resources are not in the cache.
You can see on the first day, when we put this pixel on the page, 100% of the pages
had an empty cache because this image had never been loaded before.
After about two weeks, we hit a steady state and we can see it's about 20%.
We ran this on various properties at Yahoo that had different user metrics.
This was always about the same.
This number fluctuated a little bit more, but it was always between 40 and 60%.
About half of your users come in at least once a day with an empty cache.
So why are these numbers different?
Typically, users are doing multiple page views in a session.
So even if they have an empty cache, they will come in and have an empty cache page
view, which will show up here and show up here.
But then they might do three or four more page views, which are going to be a prime
cache, because when they did their empty cache page load stuff got put into the cache.
So that's why these numbers are different.
But it still means people anchor on negative experience.
So if half of your users were coming in every day with an empty cache, and you are not taking
that into consideration, you are like, well, yeah, it's not 300 k image or script but it
will be in the cache, for about half of your users, it's not going to be in the cache.
So you can run this experiment yourself and you will get the same results.
So the cache, even if you are doing far future expires, the cache might not be doing what
you think.
And -- and here's a great study from Guy Poe over at Blaze, now Akamai, where he shows
that mobile caches are very small.
This is another reason why things you think should be in the cache won't be.
This was a study I did where I found that -- I like building Web apps and putting them
on the home screen and turned out in iOS if you do that the cache isn't used optimally.
So you can use app cache for caching.
So the way they use app cache at this manifest attribute, you give it a file name, which
is your app cache.
Manifest is a good name I think we all intuitively recognize what we are going to see here.
Here's your manifest file.
It has to start with this cache manifest header.
We will talk about the revision number in a second, but you'll want to add that.
It's got these various sections, a cache section says these are the things that I want you
to put into app cache.
The network session says these are the things that you should never put into app cache.
The fallback section says if the user is online, then use this URL.
But if they are offline, read this one from app cache.
So the browser, when the user is online, will download this one, but will also download
this one and save it into app cache.
At least right now, you have to make sure to give this a very specific content type.
Text/cache-manifest.
So it looks pretty good.
It turns out actually it's really, really, really hard and complicated to work with.
So here are some of the gotchas that you will probably run into.
I know I did.
I didn't realize -- like, I never listed my HTML document itself, .php, .HTML in the manifest
file, so I just assumed it wouldn't be put into app cache.
But if your HTML document uses the manifest attribute, then it's going to be saved to
app cache.
This was really confusing for me because I had a log-in box on the front page.
And if the user came in and their app cache was empty and they weren't logged in, the
logged-out version of the page would be saved; every time they came back, that's what they
would see even after logging in.
So that's a little confusing.
If anything in the manifest list 404s, nothing is saved.
You get about five meg, which is pretty good.
Yeah, so this is interesting, suppose you change one of the resources listed in the
manifest file, like an image, you would think that the next time the user opens the app,
they would see that new image.
They don't.
You actually have to change something in the manifest file to make it different, and that's
why the revision number was in there on the previous slide.
That's what I do is I have that automatically updated whenever I update through source code,
through my source code control system, it will automatically update that revision number,
so the manifest is always touched whenever I update a resource, and this was really confusing
to me.
Even if you do, you know, rev the manifest file, the user still won't see the change
until the second time they open the app.
So I think this is really interesting, and it's a real gotcha', so I wanted to walk through
it in more detail, so let's suppose you go home today and you build mobile Web app that
uses app cache, or a desktop app that uses app cache, and it's got this awesome green
logo that the designer gave you, and you list that into your app cache manifest file, so
you push that tonight, tomorrow, the first user ever downloads your app, and the app
cache is obviously empty.
They've never seen this before, and so the browser fetches the manifest file and in there
the logo is listed so the browser downloads that, puts it into app cache, and renders
the app to the user so the user sees the awesome green logo.
So now suppose tomorrow night you go, you know, I really think an orange logo would
be better, so you push to your server this new orange logo, and you remember to change
the version number in the manifest file.
So the logo is new, the manifest file is new.
And on -- today's Friday, so you do that Saturday night, so on Sunday, the user -- same user
loads the app again, and the browser says, okay, well, this app has a manifest file associated
with it.
Do I have any of those resources in my app cache?
Oh, I do.
I need logo.jif, or i have logo.jif in my app cache; it's this pretty green logo.
Even though I've already pushed an orange logo to my server, the browser is ignoring
that.
That's why it can work offline.
It can say I have this stuff in app cache, let me load as much as I can without using
the network.
And so it displays that app cache logo to the user.
But now what it does is it's -- once it's rendered the app with the old out-of-date
logo, it fetches the manifest file, it detects that it's changed and so then it checks all
other resources in the manifest file and it gets the new version of the logo which is
orange, it saves that to app cache, so if the user reloads the app, a second time, it
will -- the browser will look in app cache and now it has the orange logo, so it renders
the orange logo to the user, it fetches the manifest file which hasn't changed and so
it's done.
So it's really taken these two loads -- after I update a resource it takes two loads for
the user to see the changes.
Now, there is a work around to this, it's not that hard, but not that easy.
There's this update ready part.
The implementation is pretty easy.
I can track this.
But it's what do I want to do with the user experience?
So in the background, the browser detected that there was a new logo, and it fires this
update ready, but are you going to tell the user to like reload the app to see the changes?
I don't know, you have to decide for yourself.
Maybe if it's just images it's not that important.
If it's like an important JavaScript security privacy fix, then, yeah, maybe you want to
tell them to reload it, or you want to reload it without even telling them, just reload
the app.
Another way to do improved caching because we know the browser cache doesn't work super
awesome is local storage.
Really simple API.
Local storage is persistent across sessions.
If you only care about sessions, you can use session storage.
It's about five meg.
One warning, browser developers really are worried about this getting too much use because
it does a synchronous read.
Some browsers will actually read everything out of local storage, the first time you go
to that page during the session, and if you have a lot of stuff in local storage, again,
it's single-threaded so that can slow down the user experience.
So I built this bookmark that lets you look into what is stored in local storage, and
I discovered a couple of interesting things that Bing and Google search were doing, which
I hadn't thought of, and it's very cool to help with caching.
So I think this is the Google search -- Google mobile search implementation.
The first time you do a search, the HTML document will return all of these inline script and
style blocks, a lot of JavaScript and CSS, and when it's done, it iterates over those
script tags and style tags that have IDs, and it takes the content of the block, and
writes it into local storage based on the ID of that element.
So now, after I've done this first search ever on my phone, I have blocks of JavaScript
and CSS in my local storage, so now let's say I do another -- oh, and the other thing
it does is it sets a cookie that says which blocks of JavaScript and CSS have been written
into this user's local storage.
So now if I do another search, this cookie goes up to the server, and the server says,
oh, well, you're doing a search, I have to give you this block and that block and this
JavaScript and this CSS.
Let me see what you already have in local storage.
It looks at the cookie and says, oh, you already have this block, I don't have to send you
that, I don't have to send you this CSS, and for -- in the case of mobile search, it drops
the download size from about 110K to just 10K, because all that stuff is now in local
storage.
And then when the lightweight page arrives, there's some JavaScript that will pull all
of these things out of local storage and write them into the page.
So this is a really cool way to get more persistent cache.
Local storage is unaffected by other Web sites whereas the shared browser cache, if the user
visits a bunch of other Web sites that have large resources, your content might get pushed
out.
So I did a quick survey using this is what this -- I'm a good JavaScript hacker.
I'm not a good UI designer.
This is my awesome storage or bookmark list, and you can see it lets you look at what's
in the local storage and session storage, tells you how big it is, how many items it
is.
So let's just do a quick run through the Alexa Top 10 and see how local storage is being
used.
So here we have -- Google search is using it on both mobile and desktop, so that's one.
Bing is using it on mobile.
Facebook is using it on mobile.
Yahoo is maybe using it a little bit, but not really.
We're not going to count that.
YouTube, yeah, we'll count that.
Quite a bit of content on mobile.
Amazon, no.
Twitter?
Yeah, okay, we'll count that.
Five.
LinkedIn, no, I would say.
eBay, no.
MSN, no.
So about five or six of the Alexa Top 10 are using local storage, so that's an indicator
that, you know, it's worth investigating.
Why is it more -- maybe used more prevalently on mobile?
You know, the experience of not having something in the cache in mobile is worse, because the
network connection speed is so slow, also the cache is smaller on mobile, so caching
isn't awesome on desktop, but is much better on mobile, so I think that's why these top
properties started using local storage on mobile, but I would expect to see this proliferate
on desktop apps as well.
So I want to talk about font-face.
Again, pay attention to the photos, not to what I say.
So, you know, fonts, using custom fonts can create a more compelling, beautiful experience,
but people haven't really paid attention to what it does, similar to how scripts and style
sheets can block a page, what custom font files do, and so I created this table that
here's the blog post, that shows how scripts and style sheets and fonts can affect, and,
you know, "blank below in red" means that everything using this font or below it are
going to be affected.
Flash -- oh, delayed means -- blank is really bad.
It means like everything in the page is blank.
Delayed means just the element that's using the font file is affected.
Flash means once the things -- things will render, but once the resource arrives it has
to be redrawn, and so it's kind of a jerky user experience, things have to be rerenderred
and repainted.
So you can see the impact.
Even the green "good" is not really a good experience.
And so you want to use fonts kind of carefully.
And it's kind of ironic, it's kind of how these async script loader libraries make you
load their scripts synchronously.
When I talk to designers about why they're using custom fonts, even though we know it
has this impact on the user experience, they say, well, these are the most important design
elements in the page.
I'm like, "so you want the most important parts of the page to take the longest to render?"
Like, that doesn't make sense to me.
So despite my warnings, custom fonts have taken off, like they've more than doubled
in the last year, this is a chart from the HTP archive.
So they're taking off.
The good thing is the folks at Typekit and the Google fonts library have done a lot of
good work to mitigate the impact that custom fonts files have, but we can still go farther.
In fact, I think Google fonts library just announced custom fonts a few months ago.
If you don't need -- like if you're only using digits or other certain characters, like it's
just a word that you want to render in that font, you can actually create a smaller font.
The font files are typically like over 100K, so you can create one that is just the characters
that you need.
The flash of unstyled text means you draw text and then you have to redraw it, and so
what I would propose is that browsers have like an impatient fallback, like if -- I don't
want to have this flash of my text, so I'm going to wait 250 milliseconds for the font
file.
If it hasn't come back and we're drawing in a default font, and even if the font files
comes back later, I'm not going to redraw it.
I'll cache that font for the next time the user goes to the page, but I'm not going to
do that, and again, I think this is a behavior that the Google font library and Typekit loaders
do automatically for you.
Yeah.
And also, okay, I'm running short on time, so I'm going to go a little faster.
Font should be given a higher priority in caching.
Browsers are still just starting to pay attention to that, and even if a font is expired, I
might want to render with it, and do a "if modified since request", and then if I get
back, "oh, not modified?"
It's okay, I've already rendered with a font.
All I have to do is validate it.
Oh, good, I'm getting close to the end, so there's a lot more stuff I didn't talk about.
We -- you know, all of us spent a lot of time building rounded corners that downloaded a
bunch of images, so now you can do a lot of things that used to require HTP traffic, you
can do with CSS 3, so that's cool.
You have to be a little careful, these incur, you know, might incur a lot of CPU overhead
or repaints.
You can use SVG and canvas instead of downloading images.
Video tag could make starting up videos faster.
Web sockets, if you have a very chatty sort of app can be used.
Web workers, if you have like a lot of computation that you want to get out of the UI thread,
you can use Web workers, oh, for some things that we used to have to write a lot of JavaScript
or HTML for, you can do with these new built-in controls.
Again, the photo, more, infinite number of digits.
History API, we used to have to implement this in JavaScript.
Now we don't have to download all that JavaScript.
Ping is a way to avoid a redirect if you want to track something.
Don't use set time-out for animation.
Use request animation frame.
It will be faster.
You can use the native JSON parser, and here are some good resources to get more information
about this other HTML5 stuff.
So what are the takeaways?
Speed matters.
Hopefully we all agree about that.
I saw you raise your hand before.
So I'm going to hold you to that.
Pay attention to what's coming out of the Web performance working group out of the W3C.
You can use window.performance to track the timing on your pages, and even if you haven't
done that yet, if you're using Google Analytics, you can go and see the data there.
It's already been gathered for the last few months.
JavaScript blocking the UI thread is really critical.
Try to get a lot of that stuff deferred or async, and caching is really important.
I think it's one of the most important things for a fast user experience.
Browsers are improving their cache.
Mobile browsers have a lot of room to catch up on, so you can try some of these other
techniques.
And be careful about using font-face.
So before I close out, I want to mention, if you like this kind of performance stuff,
I'm sorry, but you should have been at Velocity this week.
We just finished that Wednesday.
But if you missed that, you could go to Web PERF days, the first ever, but -- well, actually,
that was yesterday.
Okay, so you missed that one.
[ Laughter ] >>Steve Souders: Oh, okay, we've got Velocity
Europe coming up in October, so you might have to go a little farther, but -- and we'll
be back next year in June for Velocity.
I also wanted to just mention this -- oh, I added this like five minutes before I came
on stage.
How can I do this, like -- I don't know, I have to go through them all.
So (indiscernible) runs this performance calendar every year, and O'Reilly took the most recent
performance calendar and put it into a book, so this just came out this week, and you can
get most of this content on the blog for the performance calendar, but the -- they were
updated, and if you like books, you can get it in book form here.
So that's it.
Thank you very much.
[ Applause ] >>Steve Souders: So I've got about four minutes,
I would be happy to answer any questions and I think they want you to use the mic.
Everyone is heading out.
>>> Would you care to expand upon font awesome?
And also to resolve some of the issues of pop-in, I found setting a fixed type for whatever
text I decide is very nice.
>>Steve Souders: What's the first one?
Expound on...
>>> Font awesome, using fonts instead of sprites?
>>Steve Souders: Oh, yeah, so you can create a custom font, you know, file, that has little
pictures, you know, kind of like wings -- what is it on windows?
The wings font, wingdings, yeah, so you can do that with a font, so if you have like really
small images that you're using now and you're downloading them as HTP requests instead of
images, instead you can download a font fall.
It doesn't have to be huge.
Maybe you have 10 of those or 20 of those, and you can download those and use those to
draw those little images, those little sprites in the page for like maybe little buttons
or things like that, and so, you know, I think that's a great idea.
You could also use sprites.
Sprites are maybe a little harder to do.
You have to create the image and know all the CSS, but the one thing I would say, if
you're using any kind of font file, is try to figure out a way to do it that doesn't
block the page, like especially in IE.
Custom font files block rendering of everything in the page, so if you could do that lazily
or something like that, that would be good, and then the second one was...
>>> Just a tip to deal with font snapping in after they loaded, the ugly hack of just
setting a fixed type for everything.
So at least it doesn't like reflow.
>>Steve Souders: Yeah, yeah, you could do that.
Yes, another question.
>>> Yeah, you said mobile browsers don't support most of those features yet, custom, you know,
desktop browsers either, so how would we test them?
>>Steve Souders: I guess I wasn't clear.
Everything I talked about is supported in mobile browsers, pretty much, and, in fact,
you're going to get -- I think that's another reason why we're seeing more HTML5 stuff on
mobile and desktop, because on desktop, there's still a lot more lingering IE6, IE7 legacy
browsers out there, so you're almost a little safer using the cutting edge stuff on mobile
than you are on desktop.
The only thing I can think about is I thought there was something -- well, the page visibility
API is only in Chrome, but all the timing stuff, local storage fonts, app cache, async
and defer attributes, all of that is supported on mobile too.
>>> Thank you.
>>Steve Souders: Yeah.
Okay, let's go here.
>>> Let's see here.
You were talking about visibility and document.webkit hidden and how that relates with click tracking
and stuff like that.
One click unsubscribes and e-mails and things like that, is that another way that we can
avoid being automatically unsubscribed?
>>Steve Souders: Oh, oh, well, but how would you -- how would you -- what's the scenario
where you would render unsubscribed page without the user seeing it?
>>> Well, if they're following links and pre-loading in the background, you might follow --
>>Steve Souders: Oh, yeah, the pre-rendering I was talking about is the developer or user
has explicitly asked to open a page, but we can just know we can do it in the background.
But, so, yeah, if you're crawling a page, that could be something that you could do
is to make sure not to -- you know, you could instrument an unsubscribed link so that it
only worked if the page was visible.
Yeah.
>>> Thank you.
>>Steve Souders: Yeah.
>>> What's your recommendation in terms of moving the script tags physically to the bottom
of the body tag versus using the defer script tag that you described?
>>Steve Souders: Yeah, I think both of those work.
One thing that we -- I only have a few seconds, so one thing we don't have time to talk about
is the importance of the onload event firing as quickly as possible, so in both cases with
defer and async and putting scripts at the bottom, you're going to block the onload link,
the onload event from firing, so really putting scripts at the bottom is almost the same as
doing defer.
It really has more to do with kind of the size of your team.
A lot of times there's, you know, 20 or 200 people working on a property, and so it's
hard to get the message out to put scripts at the bottom or like someone's code is only
going to be executed at the top and be really hard to give them a foothold in the top and
give them also a foothold in the bottom and make sure that both of those are done in sync,
so if the only place like the logging or metrics team has a place to -- a foothold in the page
is at the top, they can get the same behavior using the defer attribute as just putting
the script tag at the bottom.
Putting the script tag at the bottom is another lightweight way to avoid that blocking of
the UI thread.
Okay.
So I should wrap up.
Thank you very much.