Bookmark with del.icio.us submit Performance%20Calendar digg.com reddit

Performance Calendar

Each day this month, a web performance expert is posting an article on Performance Calendar. There is some really fantastic content here.

My contribution is Faster Ads with HTML5.

Bookmark with del.icio.us submit Progressive%20XMLHttpRequest digg.com reddit

Progressive XMLHttpRequest

Perhaps it's subtle, but the draft spec for XMLHttpRequest calls for support for progressive response handling:

4.7.6 The responseText attribute

The responseText attribute must return the result of running these steps:

1. If the state is not LOADING or DONE return the empty string and terminate these steps.

2. Return the text response entity body.

To rephrase for my purposes, responseText should return the intermediate contents of the response when an XMLHttpRequest is interrogated during the LOADING state. It'll take a little work to handle these partial responses as valid script, but let's first address browser support. Firefox and Webkit browsers already support this behavior if you set the Content-Type header of your response correctly. IE8 throws an exception when responseText is accessed before readyState reaches COMPLETE.

I ran a modified version of the streaming response tests I used in my last post to verify progressive XHR handling. The server returns several chunks in 100ms intervals that include script that indicates how much of the response was received before it is first handled by the browser.

  Bytes Buffered
Configuration Firefox 3.5 Chrome 3.0 IE 8
Tranfer-Encoding: chunked 111 536 N/A
Content-Type: text/html
Tranfer-Encoding: chunked
111 N/A N/A
Content-Type: text/plain
Tranfer-Encoding: chunked
111 85 N/A
Content-Type: application/x-javascript
Tranfer-Encoding: chunked
111 111 N/A

For Webkit browsers, it's critical to specify a Content-Type of "text/plain" or "application/x-javascript" when returning script content to an XHR for progressive handling. Seems reasonable, but it's easy to neglect. In my testing, I didn't see any change in behavior in the presence of a "charset" param.

Note that Microsoft's documentation for XMLHttpRequest now refers the to draft specification. I'm hopeful that we'll be seeing support for progressive responses soon.

Now, since we'll be interpreting partial response content as executable script, we'll need to do something to ensure that each chunk we evaluate terminates on a complete expression. For this test, I added delimiters between valid blocks of source:

window.aFunction();
// -- //
window.bFunction();
// -- //

Where //--// is the delimiter. When outputting using chunked transfer encoding, you might organize code so that a delimiter is present at the end of each chunk boundary. On each readyState change, if the state is LOADING or DONE, I call a function to read the new content, identify a safe place to trim it, and append it to a buffer.

var index = 0;
var buffer = '';
var DELIMITER = '//--//';

function handlePartialResponse(request) {
  var i = request.responseText.lastIndexOf(DELIMITER);
  if (i > index) {
    i += DELIMITER.length;
    var newChunk = request.responseText.substr(index, (i - index));
    buffer += newChunk;
    index = i;
    flushBuffer();
  }
}

Finally, we evaluate the contents of the buffer. It's not necessary to remove the delimiter, since it's a valid JavaScript comment.

function flushBuffer() {
  window.eval(buffer);
  buffer = '';
}

What would you use this for? Consider this technique for the response channel in your next Comet app or any time you're able to deliver part of a script response while doing expensive server side work to produce the rest.
Bookmark with del.icio.us submit Performance%20Implications%20of%20%22charset%22. digg.com reddit

Performance Implications of "charset".

A while back, I wrote a post documenting the progressive response handling behavior of different browsers. I was specifically interested in how many bytes must be received or how much time must pass before a browser begins to parse content. My friend and colleague, Bryan McQuade (a co-author of Google PageSpeed), recently pointed out that character encoding detection is the source of buffering delay in response handling. Specifically, in the absence of a "charset" param in the Content-Type header, a browser may buffer a large quantity of content while looking for a <meta> tag declaring the content encoding.

I set up a new round of tests to identify the impact that content encoding declarations have on progressive response handling in different browsers. As in previous tests, the server returns several chunks, in 100ms intervals, each containing script that indicates how much of the response has been received.

  Bytes Buffered
Configuration Firefox 3.5 Chrome 3.0 IE 8
Tranfer-Encoding: chunked 1134 1056 300
Content-Type: text/html
Tranfer-Encoding: chunked
204 1056 341
Content-Type: text/html
Tranfer-Encoding: chunked
...
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
166 204 218
Content-Type: text/html; charset=utf-8
Tranfer-Encoding: chunked
204 280 300

Note that the test doesn't account for content in the document <head>, so the numbers for the <meta> configuration are artificially short by ~70b.

It's clear that for Chrome and Firefox, indicating the charset has a measurable impact on performance. Now, is it more desirable to declare the charset in the Content-Type header or a <meta> tag? Darin Fisher suggests that placing it in the response header is more performant: The charset impacts how the response is parsed, so when the browser encounters the <meta> tag, it must reprocess everything it's handled so far. If you're forced to use the <meta>, place it as near as possible to the top of the document to reduce the amount of throwaway work done by the browser.
Bookmark with del.icio.us submit Firefox%20Paint%20Events%20Update digg.com reddit

Firefox Paint Events Update

I recently posted about a Firefox / Firebug extension for digging into Firefox's new MozAfterPaint events. I just posted my second update to the Firefox Addons site. In addition to highlighting the clip area of paint events, this update adds screenshots so it's possible to see the page state at the time of an event:

Note that capturing the screen for each paint event adds significant overhead, so it's wise to leave this feature disabled when not actively using it. Other handy features include the ability to view event details on the Firebug DOM tab:

And dig into the complete events details:

The "image" attribute above is a data URL of the screen capture. I imagine this will have some other practical uses. Some other event types are logged for reference, and clicking on any event will reset the base time to the time of that event, to make it easier to see how actions relate to paints:

To use this extension, you will need a 3.1+ Firefox pre-release and Firebug 1.3. You can pick up the latest version of Firebug Paint Events here.

Bookmark with del.icio.us submit Progressive%20Script%20Execution digg.com reddit

Progressive Script Execution

Recently I've been speaking to colleagues about progressive script execution, and it seems like a little-explored topic, so I'm sharing what I know. By progressive execution, I mean that scripts begin executing in the browser before the containing resource has been wholly received.

Dealing with Dynamic Response Sizes

One of the first hurdles people encounter with progressive response handling is that most HTTP responses have a Content-Length in the response header. This means that the size of the response must be known before any data is sent over the network. For static resources, this isn't such a problem because the entire response is available at once, but for dynamic resources, this means that the entire response must be determined before any part of it can be written to the network.

Imagine your web application performs an expensive operation that takes up to half a second to complete. If it takes another 500ms on average to transfer all of your HTML and CSS to users, it will take a full second to load your page. If you could transfer the bulk of that data while waiting for the operation to complete, then tack on the final bits, you might cut your response time in half.

This can be accomplished with effective use of HTTP Chunking ("Transfer-Encoding: chunked"). Chunked responses don't require a Content-Length header, so it's possible to do work after bytes have been sent to the network. While each chunk in the response will contain a header, indicating the size of the chunk, any number of chunks can be appended until a terminating delimiter is provided.

Executing Scripts Progressively

In the hypothetical example above, we were dealing with HTML and CSS, but suppose instead that we have a large amount of script to deliver with each response. Take note, external <script>s and XHRs are not progressively interpreted*. Other methods, such as inline <script>s and iframes are required. Also note, individual script blocks are not evaluated until the full contents have been received and parsed by the client. So it's advisable to split scripts into small sections, each wrapped in it's own block:

<script>
...
</script>
<script>
...
</script>
<script>
...
</script>

The ideal size of these script blocks will vary by application and the connection characteristics of your users. You might consider typical packet size (about 1460b) and the behavior of TCP Slow Start as a guide.

Browser Support and Caveats

To explore progressive execution, I implemented a simple HTTP server in Perl (View Source for Example #1), that writes several small chunks (real HTTP chunks) that look like:

<script>document.write('10: 737b: ' + n() + 'ms<br>')</script>

The fields indicate the chunk number, number of bytes written to the buffer, and a function call that outputs the milliseconds since the last script execution. I was surprised by two findings:
1) Webkit browsers don't support progressive execution at all. Ouch!
2) Other browsers don't begin parsing and executing until a byte threshhold has been reached, and this threshhold varies from browser-to-browser. In IE7, my output looks like:

0: 127b: 0ms
1: 188b: 0ms
2: 249b: 0ms
3: 310b: 969ms
4: 371b: 1015ms
...

And in Firefox 3:

0: 127b: 2ms
1: 188b: 0ms
2: 249b: 1ms
3: 310b: 1ms
4: 371b: 1ms
5: 432b: 1ms
6: 493b: 0ms
7: 554b: 1ms
8: 615b: 1ms
9: 676b: 1ms
10: 737b: 1ms
11: 799b: 0ms
12: 861b: 1ms
13: 923b: 1ms
14: 985b: 1ms
15: 1047b: 876ms
16: 1110b: 1021ms
...

This shows that the threshhold in IE7 is about 200-300b, and in Firefox3, about 1kb. While scripts won't execute until the threshhold is reached, it may still be advantageous to deliver content smaller than the threshhold early to take advantage of idle network time. Though you might consider padding your response if it enables you to provide early feedback to users.

It's not necessary to create a new chunk for each script block to achieve progressive execution, but you must be able to determine the size of each chunk before it can be written. It's also important to flush the network buffer at logical intervals (at the close of each script block, for example).

A modified version of the demo HTTP server (View Source for Example #2) demonstrates that progressive execution can be achieved within chunks. For this example, each chunk contains 5 script blocks. I precomputed the total size of each chunk, and appended the output in 1 second intervals. Output for a run in IE follows:

0: 127b: 0ms
1: 188b: 0ms
2: 249b: 0ms
3: 310b: 1016ms
4: 371b: 922ms
...

And for Firefox 3:

0: 127b: 1ms
1: 188b: 1ms
2: 249b: 1ms
3: 310b: 1ms
4: 371b: 1ms
5: 432b: 1ms
6: 493b: 1ms
7: 554b: 1ms
8: 615b: 2ms
9: 676b: 1ms
10: 737b: 1ms
11: 799b: 1ms
12: 861b: 1ms
13: 923b: 1ms
14: 985b: 1ms
15: 1047b: 1136ms
16: 1110b: 817ms
...

That concludes my overview. I'm interested in questions and ideas for further exploration.

* XHR implementations that notify when bytes are received could theoretically be evaluated progressively, but to evaluate JavaScript safely in such a context would require a fair amount of infrastructure. Also, I haven't seen this done yet, but I'd love a pointer if anyone has.