Jay Taylor's notes
back to listing indexHigh Performance Web Sites | Essential knowledge for making your web pages faster.
[web search]Q&A: Nav Timing and post-onload requests
October 30, 2012 11:29 am | 1 Comment
Today I got an email asking this question about window.performance.timing
:
I’ve noticed that on all browsers (where timing is supported), the timing stops once the readyState of the document = ‘complete’. Seems normal, but in many cases, I’ve seen web pages that load additional “stuff” via aysnc loading (mostly mktg tags) and the timing object doesn’t seem to reflect this additional load time. Is this by design?
It’s a good question so I wanted to post my response for others who might be wondering the same thing.
An increasing number of websites load resources after the window.onload event. In fact, 8 of the world’s top 10 websites have post-onload activity: Google, Facebook, YouTube, Yahoo, Windows Live, Twitter, Tencent, and Amazon.
It makes sense that you’d want to capture this activity as part of any performance metrics, so why isn’t it already part of window.performance.timing
? Remember we’re dealing with a W3C specification – the Navigation Timing specification to be exact. As with many specs, what seems intuitively simple is more difficult to capture in exact language. Looking at this processing model graph we see that the questioner is right – Navigation Timing stops at the window.onload event. We might think of extending the spec to have an “end of network activity” event that would include these post-onload requests.
Defining “end of network activity” is the tricky part. In the case of many sites, such as the 8 sites listed previously, the post-onload activity is a few HTTP requests. This is more straightforward. But what about sites that do a polling XHR every 5 seconds? Or sites that use Comet (hanging GET) or websockets? Their network activity never ends, so the Navigation Timing metrics would never complete.
There’s also a tension between wanting to capture this later activity but also wanting sites to send back information as quickly as possible. Many users (5-15% in my experience) quickly click through to the next page. For these users it’s important to fire the metrics beacon (AKA tag) before they leave the page. The two key questions for this issue become:
- How can post-onload activity be measured?
- When should the timing metrics be beaconed back?
It’s possible that Navigation Timing could be extended to have an “end of network activity” value. For sites that have infinite network activity the specification could have language that set this value in the absence of network activity for N (2?) seconds or after a maximum of M (10?) seconds after window.onload. I encourage people in favor of this idea to send email to public-web-perf@w3.org (with [NavigationTiming] at the start of the subject line).
Instead of a high level “end of network activity” measurement, web developers can get more fine grained measurements today. Many of the post-onload HTTP requests are scripts, images, and XHRs that can all be timed individually with JavaScript. In the future the Resource Timing spec will provide this per-request level of timing information. Developers of websites that have infinite post-onload activity can make their own decisions about what to include in their post-onload activity measurements.
With regard to when the timing metrics should be beaconed back, it’s important to send a beacon as quickly as possible to get information before the user does a quick click through. Therefore, I recommend sending the Nav Timing data in a beacon as part of window.onload. (See sample code in A Practical Guide to the Navigation Timing API.) For sites that want to measure post-onload activity, I recommend sending a second beacon with this additional information. Sending two beacons should have a minimal performance impact for the user, network, and backend server. If the delta in the number of first vs second beacons is within a tolerable range, then the website owner could choose to send only the latter beacon containing all the performance information.
Cache is King
October 11, 2012 8:11 pm | 10 Comments
I previously wrote that the keys to a fast web app are using Ajax, optimizing JavaScript, and better caching.
- Using Ajax reduces network traffic to just a few JSON requests.
- Optimizing JavaScript (downloading scripts asynchronously, grouping DOM modifications, yielding to the UI thread, etc.) allows requests to happen in parallel and makes rendering happen sooner.
- Better caching means many of the web app’s resources are stored locally and don’t require any HTTP requests.
It’s important to understand where the benefits from each technique come into play. Using Ajax, for example, doesn’t make the initial page load time much faster (and often makes it slower if you’re not careful), but subsequent “pages” (user actions) are snappier. Optimizing JavaScript, on the other hand, makes both the first page view and subsequent pages faster. Better caching sits in the middle: The very first visit to a site isn’t faster, but subsequent page views are faster. Also, even after closing their browser the user gets a faster initial page when she returns to your site – so the performance benefit transcends browser sessions.
These web performance optimizations aren’t mutually exclusive – you should do them all! But I (and perhaps you) wonder which has the biggest impact. So I decided to run a test to measure these different factors. I wanted to see the benefits on real websites, so that pointed me to WebPagetest where I could easily do several tests across the Alexa Top 1000 websites. Since there’s no setting to “Ajaxify” a website, I decided instead to focus on time spent on the network. I settled on doing these four tests:
- Baseline – Run the Alexa Top 1000 through WebPagetest using IE9 and a simulated DSL connection speed (1.5 Mbps down, 384 Kbps up, 50ms RTT). Each URL is loaded three times and the median (based on page load time) is the final result. We only look at the “first view” (empty cache) page load.
- Fast Network – Same as Baseline except use a simulated FIOS connection: 20 Mbps down, 5 Mbps up, 4ms RTT.
- No JavaScript – Same as Baseline except use the new “noscript” option to the RESTful API (thanks Pat!). This is the same as choosing the browser option to disable JavaScript. This isn’t a perfect substitute for “optimizing JavaScript” because any HTTP requests that are generated from JavaScript are skipped. On the other hand, any resources inside NOSCRIPT tags are added. We’ll compare the number of HTTP requests later.
- Primed Cache – Same as Baseline except only look at “repeat view”. This test looks at the best case scenario for the benefits of caching given the caching headers in place today. Since not everything is cacheable, some network traffic still occurs.
Which test is going to produce the fastest page load times? Stop for a minute and write down your guess. I thought about it before I started and it turned out I was wrong.
The Results
This chart shows the median and 95th percentile window.onload time for each test. The Baseline median onload time is 7.65 seconds (95th is 24.88). Each of the optimizations make the pages load significantly faster. Here’s how they compare:
- Primed Cache is the fastest test at 3.46 seconds (95th is 12.00).
- Fast Network is second fastest at 4.13 seconds (95th is 13.28).
- No JavaScript comes in third at 4.74 seconds (95th is 15.76).
Here are the responses gathered from the attendees:
Favorite Performance Tool:
- WebPagetest
- Cuzillion
- Chrome Dev Tools
- Speed Tracer
- Performance Analyzer from Site Confidence (pay)
- SPOF-O-Matic, 3PO for YSlow
- Wireshark
- PageSpeed, YSlow
- dynaTrace Ajax Edition and SpeedoftheWeb
- HTTP Archive
- Critical Path Explorer – part of PageSpeed Insights
- PhantomJS
- mobile remote debugging: Weinre, jsconsole.com, Opera Dragonfly, Chrome for Android
- Apache Bench (ab)
- Show Slow
- Browserscope
- Tilt, DOM Monster
- Mobileperf Bookmarklet
- chrome://net-internals
- Redbot
- SpriteMe
- Boomerang, Episodes
- wget, telnet
- Wappalyzer
- Netalyzer
- Shunra NetworkCatcher Express
- Packet Flight
- Fiddler, Charles
- CSS Lint, JSLint
- GTMetrix
Updates:
- Torbit Insight
- Grunt.js
- sitespeed.io
- SSL Server Test
- SPDY Indicator (Firefox, Chrome), SPDYCheck.org
- KITE, MITE
- Compass (CSS)
- Soke, Seige, Tsung (load testing)
- SpeedCheckr
Missing Tools:
- When analyzing a website need a tool that calculates the average delta between last-modified date and today and compare that to the expiration time. The goal is to indicate to the web developer if the expiration window is commensurate with the resource change rate. This could be part of PageSpeed, YSlow, and HTTP Archive, for example.
- Automated tool that determines if a site is using a blocking snippet when an async snippet is available. For example, PageSpeed does this but only for Google Analytics.
- Tools that diagnose the root cause for rendering being delayed.
- Easier visibility into DNS TTLs, e.g., built into Chrome Dev Tools and WebPagetest.
- Backend tool that crawls file directories and optimizes images. Candidate tools: Yeoman, Wesley.
- Nav Timing in (mobile) Safari.
- Better tools for detecting and diagnosing memory leaks.
- Web timing specs for time spent on JavaScript, CSS, reflow, etc. (available in JavaScript).
- Tools to visualize and modify Web Storage (localStorage, app cache, etc.).
- Tools to visualize and clear DNS cache.
- A version of JSLint focused on performance suggestions.
- A tool that can diff two HAR files.
Updates:
- in-browser devtools letting you drill into each resource fetched or cached, listing the full set of reasons (down to the combination of http headers at play in the current and, as applicable, a prior request) for why that resource was or wasn’t loaded from the cache, when it would get evicted from cache and why: https://bugs.webkit.org/show_bug.cgi?id=83986
This was stream of consciousness from the audience. It’s not an exhaustive list. Do you have a favorite web performance tool that’s not listed? Or a performance analysis need without a tool to help? If so, add a comment below. And consider organizing WebPerfDays in your area. Aaron, Stephen, and I would be happy to help.
Async Scripts – Cached?
September 24, 2012 12:25 pm | 4 Comments
I want to re-run the real user cache experiment that Tenni Theurer and I ran back in 2007. I’m designing the experiment now and will share that design in this blog when it’s well-baked. One change is I’d like to use an external script as the cached response that is tested. Another change is I want the experiment to be a snippet that any website can embed. That allows me to crowdsource results from websites with a wider range of session behaviors, user profiles, browsers, etc.
Since I’ll be asking websites to embed this 3rd party script, it’s important that it not harm performance and avoid frontend SPOF. I’ll do this using JavaScript to dynamically request the external script using the typical createElement-insertBefore pattern:
var newscript = document.createElement("script"); newscript.async = true; newscript.src = document.location.protocol + "//NOTstevesouders.com/testscript.js"; var s0 = document.getElementsByTagName('script')[0]; s0.parentNode.insertBefore(newscript, s0);
But I wondered: Does loading an external script this way affect caching behavior?
I’ve been using this pattern for years and know that caching headers for dynamically-loaded scripts are respected in all the major desktop & mobile browsers, but what about other browsers? To answer this question I created a Browserscope user test last week. The Caching Async Scripts test page loads a script dynamically. The script has a far future expiration date so on the next page it should be read from cache. This is tested by measuring the script’s load time – normally it takes 6 seconds to load so if it’s far less than that it must have been read from cache.
I tweeted the test’s URL asking people to run the test. Thanks to everyone who ran it! The crowdsourced Browserscope results show data for over sixty browsers including Blackberry, Epiphany, and PlayStation. Happily, and surprisingly, it shows that every browser honors caching headers for scripts loaded dynamically. That’s great news in general, and with regard to re-running the cache experiment means that I can feel comfortable using this pattern to load the cached script while avoiding frontend SPOF.
Preferred Caching
September 12, 2012 8:06 am | 9 Comments
In Clearing Browser Data I mentioned Internet Explorer’s “Preserve Favorites website data” option. It first appeared in Internet Explorer 8′s Delete Browsing History dialog: