Profile

Cover photo
Bryan McQuade
134,392 views
AboutPosts

Stream

Bryan McQuade

Discussion  - 
 
My Chrome Dev Summit talk on Instant Mobile Web Apps. Summary:
* render the initial view on the server, not the client. client-side rendering is a mobile performance anti-pattern.
* minimize render blocking resources
    * eliminate blocking JS in the initial rendering path
    * minimize (possibly inline) blocking CSS in the initial rendering path. this also means not inlining images in CSS as data URIs. doing so is harmful for time to initial render.
* load content needed to render parts of the app that are not in the initial view in a way that doesn't block rendering of the initial view (async)

Slides: https://docs.google.com/presentation/d/1z49qp03iXAJIkbXaMtCmWW_Pnnq-MzXGW139Xw8-paM/present#slide=id.p19
12
7
Norbert Sana's profile photoLuca Piazzoni's profile photo
Add a comment...

Bryan McQuade

Shared publicly  - 
 
Am I the only person seeing Chrome crash repeatedly when trying to read this article: http://www.theonion.com/articles/let-me-explain-why-miley-cyrus-vma-performance-was,33632/

I'm on a Mac using dev channel.

Filed a bug: https://code.google.com/p/chromium/issues/detail?id=300779 - update it if you also see a crash.
1
Malte Ubl's profile photoPaul Irish's profile photo
3 comments
 
The three of us make up 50% of the reporters of this major bug. Way to go, us!
Add a comment...

Bryan McQuade

Shared publicly  - 
 
 
Google is definitely run for the benefit of our users; see here for alternate history of why corporations are run for shareholder value, or customers

http://www.forbes.com/sites/stevedenning/2013/06/26/the-origin-of-the-worlds-dumbest-idea-milton-friedman/
3
2
Peter Burns's profile photoJon Perry's profile photo
 
Good leadership would snap our society back into a healthy outlook much like a sail snaps full of wind when it's on a good heading.  Harnessing the wind creates the value.  The rest are just hanger's on.
Add a comment...

Bryan McQuade

Shared publicly  - 
 
Objects in mirror may be sooner or later than they appear.
6
Dave Mankoff's profile photo
 
Add a comment...

Bryan McQuade

Shared publicly  - 
8
1
Jan-Willem Maessen's profile photoBryan McQuade's profile photoDavid Corbacho's profile photoJody Shapiro's profile photo
4 comments
 
ok, I understand. Thanks for sharing your thoughts anyway, it's a difficult problem to tackle. And  I didn't understand neither why SPDY can be useful here.. that's why I saved the post "to read later"
Looking forward to read your conclusions
Add a comment...

Bryan McQuade

Shared publicly  - 
 
Just say no to reimplementing the browser's parser in JavaScript.

Here we have a library from Mobify (https://hacks.mozilla.org/2013/03/capturing-improving-performance-of-the-adaptive-web/) that allows you to "capture" the HTML in the document before the browser parses it. You get a chance to manipulate the content to indicate which image assets should get loaded by the browser.

It's clear that there is a real problem in browsers today that the Mobify team is trying to solve: browsers do not understand which image assets are actually going to be needed for responsive pages, so they tend to try to download all of the assets, which is obviously wasteful and also harmful for performance.

But the solution provided here is actually much worse than just loading all the image assets. Here's what the capturing API does:

1. inject a plaintext tag very early in the document:
   // Prevent the browser from downloading website resources
   document.write('<plaintext style="display:none">');
The plaintext tag never closes so all HTML that comes after it is parsed as plain text. Essentially this is a way of turning off the browser's HTML parser (and lookahead parser!) from JavaScript.

2. load some external JavaScript libraries needed to perform the capturing operations and prioritize which resources should be loaded

3. once the capture code loads, parses, and executes, create a child HTMLDocument which is used to parse everything after the plaintext tag in a new document context

4. invoke a callback in the main application that manipulates the document to enable/disable certain DOM elements

5. once the child HTMLDocument manipulation is complete, replace the main document's contents with this modified child document's contents

6. now the browser finally gets a chance to render some content to the screen

On the one hand, this is really cool. You just implemented a smarter HTML parser that understands media queries in JavaScript. On the other hand, you just reimplemented part of the browser... in JavaScript.

Let's dig a little deeper into what this means from a page load performance perspective. How much delay have we introduced to rendering the page as a result of loading the document this way? If we assume a mobile network round trip of 250 milliseconds and that we are loading mobify from a CDN, that's 750ms (DNS, TCP, request/response) blocking time before the browser even receives the first byte of mobify. Then it has to parse and execute mobify which will be non-zero time on a mobile device (let''s say 100ms), then it has to parse the document's contents in the child document (let's say another 100ms), then it has to copy the modified document's contents back to the main document (let's say another 100ms). So far we're already up over 1 second.

But it's actually even worse than this. None of the mobify code can execute until the main HTML has been fully downloaded. If the HTML document is large-ish (say, 10s of kB compressed), we're looking at incurring multiple additional round trips due to TCP congestion window growth before we even begin executing the mobify code. Let's say we incur 2 window growth round trips, for an additional 500ms.

Once this is all done, the stylesheet after the plaintext tag can finally begin downloading. That'll incur another round trip or 2, maybe more if we have to grow the TCP congestion window while downloading it.

Once this is done, after 2+ seconds on a mobile network, the browser can finally start rendering some content to the screen. It's hard to look at this as a performance win.

By trying to re-implement part of the browser in JavaScript, we've eliminated the browser's ability to parse or render any real page content, serializing the real parser behind the download, parse, and execution of external mobify JavaScript resources. It's going to be really hard to make up for this by eliminating the download of images. Keep in mind that JavaScript and CSS are parser and renderer blocking, whereas image assets do not block the parser or the renderer. Downloading more parser blocking resources in exchange for fewer non-blocking resources is very unlikely to be a performance win.

I am glad that the Mobify team is trying to improve responsive image efficiency, but solutions like this really need to live in the browser. The browser has so much more insight into the state of the document via its lookahead downloader, its ability to parse and render HTML in a streaming fashion, etc. It also doesn't have to download its parser from a web server (obviously), so none of those network delays are incurred by the browser's parser.

When you discover a shortcoming in the way web browsers parse your pages, rather than trying to implement a smarter browser in JavaScript, instead work on making the browsers themselves smarter. Open bugs with the browser vendors (or submit patches!), explain the problems you are encountering, and help the browser developers to understand what they need to do to make your pages load more efficiently.

Just say no to reimplementing the browser in JavaScript.

Update: to demonstrate the performance cost of using this solution on a high-latency (e.g. mobile) connection, here are two example pages, one that includes a single image, and another that includes the same image but loads the Mobify capture framework first. This isn't a real responsive page; the point of this demo is to show how much delay is added to fetching any of the assets on your page when you use Mobify capture.

First, the simple page:
http://www.modspdy.com/nocapture_example.html

And now the same page loading Mobify capture first:
http://www.modspdy.com/capture_example.html

Now, webpagetest results for each, using Chrome desktop on a high latency network (250ms round trip):
Simple page (without Mobify capture):
http://www.webpagetest.org/result/130405_5N_THC/1/details/
the image asset starts downloading at 810ms.

And the page with Mobify Capture:
http://www.webpagetest.org/result/130405_RK_TFB/1/details/
the image asset starts downloading at 2.57 seconds.

So we see that there is a roughly 1.75 second latency penalty as a result of using Mobify capture for this network configuration.
15
19
george oloo's profile photoGiovanni Savastano (gsavastano)'s profile photoMichael Cohen's profile photoEddie Kay's profile photo
16 comments
 
Hi Bryan!

Thanks again for your analysis of Capturing, this has been a great discussion. I setup my own test very similar to yours that gives a more accurate number regarding Capturing.  There are a few reasons why your test wasn't representing the penalty of Capturing as well as it could have:  

1) the Mobify.js library was not gzipped, this only happens on the first request to our CDN edge nodes -- subsequent requests are automatically gzipped so testing with gzip on is the accurate approach. It is gzipped on the origin now, so this is no longer a problem.

2) two requests were made, one for the mobify.js library and one for the main.js executable (these can/should be combined into one).

3) it does not account for subsequent requests on other pages, where the capturing file is cached and the penalty of Capturing is in the tens of ms. 

I've created some speed tests of my own that address #1 and #2:

Your test (no Capturing):
http://www.webpagetest.org/result/130405_5N_THC/1/details/ 

Your test (w/ Capturing):
http://www.webpagetest.org/result/130405_RK_TFB/1/details/

My test (w/ Capturing):
http://www.webpagetest.org/result/130408_3R_1444/1/details/

My results show that it takes 1.6 seconds to load the initial image asset, vs the 2.6 seconds in your test. My index.html file also takes about 1.1 seconds to finish, making the penalty cost of the initial request about ~0.5s. Also, I linked to a performance test in my article that runs Capturing over 100 iterations in an iframe, in order to measure the average performance penalty, try it out for yourself:

http://cdn.mobify.com/mobifyjs/examples/capturing-grumpycat/performance-test.html

Just to reiterate - this isn't a silver bullet solution, but it can be useful for a lot of people, and can definitely be a useful tool in the developer toolbox! Capturing will always have an overhead cost, but the question will always be, does the overhead cost of Capturing outweigh the performance gains that it can bring you? When the answer is yes, then Capturing can be very useful.


~Shawn
Add a comment...

Bryan McQuade

Shared publicly  - 
 
My Chrome Dev Summit talk on Instant Mobile Web Apps. Summary:
* render the initial view on the server, not the client. client-side rendering is a mobile performance anti-pattern.
* minimize render blocking resources
    * eliminate blocking JS in the initial rendering path
    * minimize (possibly inline) blocking CSS in the initial rendering path. this also means not inlining images in CSS as data URIs. doing so is harmful for time to initial render.
* load content needed to render parts of the app that are not in the initial view in a way that doesn't block rendering of the initial view (async)

Slides: https://docs.google.com/presentation/d/1z49qp03iXAJIkbXaMtCmWW_Pnnq-MzXGW139Xw8-paM/present#slide=id.p19
6
Add a comment...

Bryan McQuade

Shared publicly  - 
 
We launched a new version of PageSpeed Insights today:
http://developers.google.com/speed/pagespeed/insights/

It's faster, has a cleaner and more intuitive UI, and emphasizes mobile performance. Give it a try!
Dismiss PageSpeed Insights has a new look and feel! The PageSpeed score has been updated to better reflect page performance across a variety of devices. PageSpeed Make your web pages fast on all devices. ANALYZE. Analyzing. 0% complete. Cancel ...
12
3
Cindy Krum's profile photoJean Ceugniet's profile photo
Add a comment...

Bryan McQuade

Shared publicly  - 
 
 
Manhattan from 2000 feet: above Chelsea #aerialphotograpy  
2
Add a comment...

Bryan McQuade

Shared publicly  - 
 
Happened to come across a Tesla service center while out driving. Had to stop and check them out.
6
kenji matsuoka's profile photo
 
Cool Tesla
Add a comment...

Bryan McQuade

Shared publicly  - 
 
Interesting read. "for a member of the minority out-group, there is frequently no action that will be accepted as "right" if it includes the assertion that the majority did something offensive."
I've been watching the whole Adria Richards fiasco with a sense of horror and disgust. I'm finally going to say something, but for the most part, it's going to be indirect. See, I'm a white guy, bo......
1
1
Dave Mankoff's profile photo
Add a comment...

Bryan McQuade

Shared publicly  - 
 
I'm struggling to figure out when/why I should use the auto keyword in my C++ code.

For instance I find myself wanting to use it in the context of iterating over a collection, e.g.
vector<Foo> foos;
for (auto foo : foos) {
...
}

What exactly is auto doing here? Is it interpreted strictly as:
vector<Foo> foos;
for (Foo foo : foos) {
...
}

or is it
vector<Foo> foos;
for (const Foo& foo : foos) {
...
}

or if I want const& do I need to say
vector<Foo> foos;
for (const auto& foo : foos) {
...
}

I guess I fail to see how the auto keyword makes code more readable. I'd rather just be explicit about the type so others reading the code can see exactly what the type is. auto is easier for me to type, harder for others to understand.

I suppose it's useful when dealing with really long types, but that's what typedefs are for, no?

When do you use the auto keyword in your code?
1
Andrew Pierson's profile photo
 
If you have a collection of different types, auto can switch between them on the fly. At least I think so. I went to a presentation on C++0x a few years ago by Bjarne Stroustrup, so it's a bit hazy. 
Add a comment...
Basic Information
Gender
Male
Links