progressive downloads and rendering

Post on 14-Feb-2016

23 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

Progressive downloads and rendering. Stoyan Stefanov, Yahoo! HighLoad ++, Moscow, 2010 http://slideshare.net/stoyan/. About me. YSlow 2.0. Why progressive?. Importance of performance. Psychology, physiology Effects of waiting “Time is money” Make people happy. Perception. - PowerPoint PPT Presentation

TRANSCRIPT

Progressive downloads

and rendering

Stoyan Stefanov, Yahoo! HighLoad++, Moscow, 2010http://slideshare.net/stoyan/

About meYSlow 2.0

Why progressive?

Importance of performance• Psychology, physiology • Effects of waiting• “Time is money”• Make people happy

Perception

Perception

Perception

Perception

Time is relative• Sometimes crawls• Sometimes flies• “it depends”

Durations

actual

expectedperceived

rem’d

time

It feels slower when…• Unpleasant• Unknown• Boring• Too much to keep track

First time experience• Unfamiliar = slow• Optimize empty cache or

there will be no full cache

So… go progressive!

But before we begin…

The basics• Reducing the # HTTP• Gzip• Minification• Image smushing• Expires• CDN

The basics• Yahoo!’s best practices +

YSlowhttp://developer.yahoo.com/performance/

• Google’s too + Page Speed

http://code.google.com/speed/

Progressive

Progressive enhancement

Progressive downloads

Progressive rendering

Agenda1. Prevent download blocks:

scripts, styles, CC, favicon2. Ways to render sooner:

flush, data URIs, lazy loading, lazy evaluation, preloading, animations

Blocking JavaScript

JavaScript blocks

htmljs

pngpng

JavaScript blocks• A no-no!

<script src="jquery.js"></script><script src="jquery.twitter.js"></script><script src="jquery.cookie.js"></script><script src="myapp.js"></script>

This waterfall looks ridiculous

htmljs

pngpng

jsjs

js

JavaScript at the bottom

html

js

pngpng

Non-blocking JavaScript• defer and async• Defer: IE innovation, ok to

delay, but keep order• Async: HTML5, whatever<script async src="my.js"

onload="doIt()"></script><script defer src="my.js"

onload="doIt()"></script>

defer and async timeline

DOMContentLoaded load

async

defer

Non-blocking JavaScript• Asynchronous loading

var h, js = document.createElement('script');js.src = 'myscript.js';h = document.getElementsByTagName('head')[0];h.appendChild(js);

htmljs

pngpng

Non-blocking JavaScript• Others:

- iframe- XHR- <object>- …

CSS and rendering

Worst enemy?

CSS

CSS blocks rendering• The worst component type• Place way at the top• @media print, etc in the same external CSS

http://www.phpied.com/delay-loading-your-print-css/http://www.phpied.com/rendering-styles/

CSS

CSS

CSS blockdownloads?

But they do block:• When followed

by an inline script• When in conditional

comments

Inline CSS• Google search• Bing.com: inline + postload

Same domain• If you split across domains• and if you don’t use CDN• Saves a DNS lookup

• e.g. Google and Bing’s CDN

CC block

Normal page

With conditionally commented CSS file

http://www.phpied.com/conditional-comments-block-downloads/

What…?! Case #1 <link type="text/css" rel="stylesheet" href="1.css"> <!--[if IE 6]> <link type="text/css" rel="stylesheet" href="ie.css"> <![endif]-->

What…?! Case #2<!--[if IE 6]> <body class="ie6"> <![endif]--><!--[if !IE]><!--> <body><!--<![endif]-->

Solution for case #1<!DOCTYPE html><!--[if IE 6]><![endif]-->

<html> ...

Solution for case #2<!--[if IE 6]> <html class="ie6"> <![endif]--><!--[if !IE]><!--> <html><!--<![endif]-->

Blocking favicon

Flush

flush() earlyhtml

pngjs

css

html

pngjs

css

flush()<html><head> <script src="my.js"

type="text/javascript"></script> <link href="my.css"

type="text/css" rel="stylesheet" /></head>

<body> ....

<?php flush() ?>

Chunked encodingHTTP/1.1 200 OKContent-Type: text/plainTransfer-Encoding: chunked

25This is the data in the first chunk

1Cand this is the second one

0

Chunked encoding

• Progressive rendering- Semantic app chunksvs.- Server-level chunks

Progressive renderingChunk #1

Chunk #2

Chunk #3

<!doctype html><html><head><title>My App</title></head><body> <div id="header"> <img src="logo.png" /> ... </div> <!-- end of chunk #1 --> ... The full body of the page ... <!-- end of chunk #2 -->

<script src="all_20100925.js"></script></body></html> <!-- end of chunk #3 -->

Progressive + source order

1

23

4

HTTP chunking: not only HTML

HTTP chunking: not only HTML• Google Instant• /*""*/ - delimited JSON

pieces• Chunk #1 suggestions• Chunk #2 results

http://tinyurl.com/chunkview

Data URIs

Fewer HTTP requests• Inline images:

in CSS spriteswith data: URI scheme

http://csssprites.com http://spriteme.org

Fewer HTTP requests• data: URI scheme

$ php -r "echo base64_encode(file_get_contents('my.png'));”iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAGElEQVQIW2P4DwcMDAxAfBvMAhEQMYgcACEHG8ELxtbPAAAAAElFTkSuQmCC

Fewer HTTP requests• data: URI scheme

background-image: url("data:image/png;base64,iVBORw0KG...");

Fewer HTTP requests• data: URI scheme

<img src="data:image/png;base64,iVBOR..." />

Both• flushes• data: URIs

Fewer HTTP requests• data: URI scheme• works in IE!...

Fewer HTTP requests• data: URI scheme• works in IE8!

Fewer HTTP requests• data: URI scheme• MHTML for IE < 8

MHTML • MIME HTML• Works in IE 6,7• Indeed it actually absolutely does work in IE7/Vista too

http://phpied.com/the-proper-mhtml-syntax/

MHTML - one partContent-Location: myimageContent-Transfer-Encoding: base64

iVBORw0KGgoAAAANSU....U5ErkJggg==

MHTML - multi partsContent-Type: multipart/related; boundary="MYSEPARATOR"

--MYSEPARATOR

[here comes part one]

--MYSEPARATOR

[here's part two]

--MYSEPARATOR--

The double-dash of doom

MHTML.css – all together/*Content-Type: multipart/related; boundary="MYSEPARATOR" --MYSEPARATORContent-Location: myimageContent-Transfer-Encoding: base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAD....U5ErkJggg==--MYSEPARATORContent-Location: anotherContent-Transfer-Encoding: base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAA....U5ErkJggg==--MYSEPARATOR--*/.myclass { background-image:url(mhtml:http://example.org/styles.css!myimage);}.myotherclass { background-image:url(mhtml:http://example.org/styles.css!another);}

MHTML: inline too<!doctype html><html> <head> <title>Look Ma' No HTTP requests</title> <style type="text/css">/*Content-Type: multipart/related; boundary="_"

--_Content-Location:locolocoContent-Transfer-Encoding:base64

iVBOR...CC--_Content-Location:pollolocoContent-Transfer-Encoding:base64

iVBOR....gg==--_--*/.image1 { background-image: url("data:image/png;base64,iVBOR...CC"); /* normal */ *background-image: url(mhtml:http://...html!locoloco); /* IE < 8 */}.image2 { background-image: url("data:image/png;base64,iVBOR...gg=="); /* normal */ *background-image: url(mhtml:http://...html!polloloco); /* IE < 8 */}body { font: bold 24px Arial;} </style> </head> <body> <h1>MHTML + Data:URIs inline in <code>style</code></h1> <p class="image1">hello<br>hello</p> <p class="image2">bonjour<br>bonjour</p> </body></html>

http://phpied.com/inline-mhtml-data-uris/

<!doctype html><html> <head> <title>Look Ma' No HTTP requests</title>

<style type="text/css"> ...

/*Content-Type: multipart/related; boundary="_"

--_Content-Location:locolocoContent-Transfer-Encoding:base64

iVBOR...CC--_Content-Location:pollolocoContent-Transfer-Encoding:base64

iVBOR....gg==--_--*/

.image1 { background-image: url("data:image/png;base64,iVBOR...CC"); /* normal */ *background-image: url(mhtml:http://...html!locoloco); /* IE < 8 */}.image2 { background-image: url("data:image/png;base64,iVBOR...gg=="); /* normal */ *background-image: url(mhtml:http://...html!polloloco); /* IE < 8 */}body { font: bold 24px Arial;}

... </style>

</head> <body> <h1>MHTML + Data:URIs inline in <code>style</code></h1> <p class="image1">hello<br>hello</p> <p class="image2">bonjour<br>bonjour</p> </body></html>

MHTML + data URI• X-browser single request web apps

Single request• WT☠?• Separation of concerns• Content-presentation-behavior• yes, it’s a tradeoff

MHTML + data URI• drawback: repeats the same encoded image• solutions: - browser-specific CSS - keep close = better gzip - or… an ingenious hack

Single stream MHTML/data URI• image header + css + data/9j/4AA0;background-image:url(data:image/jpeg;base64;00,/9j/4AA0

Reality:

IE:

Others:

http://habrahabr.ru/blogs/webdev/90761/

/*Content-Type: multipart/related; boundary="granitza"

--granitzaContent-Type: text/css;

*/#myid {/*--granitzaContent-Location: myimageContent-Transfer-Encoding: base64Content-Type: image/jpeg;*/

/9j/4AA0;background-image:url(data:image/jpeg;base64;00,/9j/4AAQSkZJRgA...);/*--granitzaContent-Type: text/css;

*/background-image: url(mhtml:http://localhost/my.css!myimage) !ie;}/*--granitza--*/

/*Content-Type: multipart/related; boundary="granitza"

--granitzaContent-Type: text/css;

*/#myid {/*--granitzaContent-Location: myimageContent-Transfer-Encoding: base64Content-Type: image/jpeg;*/

/9j/4AA0;background-image:url(data:image/jpeg;base64;00,/9j/4AAQSkZJRgA...);/*--granitzaContent-Type: text/css;

*/background-image: url(mhtml:http://localhost/my.css!myimage) !ie;}/*--granitza--*/

???

/*Content-Type: multipart/related; boundary="granitza"

--granitzaContent-Type: text/css;

*/#myid {/*--granitzaContent-Location: myimageContent-Transfer-Encoding: base64Content-Type: image/jpeg;*/

/9j/4AA0;background-image:url(data:image/jpeg;base64;00,/9j/4AAQSkZJRgA...);/*--granitzaContent-Type: text/css;

*/background-image: url(mhtml:http://localhost/my.css!myimage) !ie;}/*--granitza--*/

/*Content-Type: multipart/related; boundary="granitza"

--granitzaContent-Type: text/css;

*/#myid {/*--granitzaContent-Location: myimageContent-Transfer-Encoding: base64Content-Type: image/jpeg;*/

/9j/4AA0;background-image:url(data:image/jpeg;base64;00,/9j/4AAQSkZJRgA...);/*--granitzaContent-Type: text/css;

*/background-image: url(mhtml:http://localhost/my.css!myimage) !ie;}/*--granitza--*/

???1

2

3

Single stream MHTML/data URI• And for <img> too!

Single stream <img><h2>Hello Kitty</h2><!--granitzaContent-Location: myimageContent-Transfer-Encoding: base64Content-Type: image/gif2 invalid MHTML headers lines followed by data--><![if gt IE 7]><img width="16" height="16" src="data:image/gif;base64,

R0lGODl ... FxMKVvDijNQaodOl+N5Pk+pmIX7brGweCg4SCEhEAOw=="><![endif]>

<!--[if lt IE 8]><img src="mhtml:http://.../bolknote.html!myimage" width="16" height="16"><![endif]-->

<p> more page... </p>

Single stream <img><h2>Hello Kitty</h2><!--granitzaContent-Location: myimageContent-Transfer-Encoding: base64Content-Type: image/gif2 invalid MHTML headers lines followed by data--><![if gt IE 7]><img width="16" height="16" src="data:image/gif;base64,

R0lGODl ... FxMKVvDijNQaodOl+N5Pk+pmIX7brGweCg4SCEhEAOw=="><![endif]>

<!--[if lt IE 8]><img src="mhtml:http://.../bolknote.html!myimage" width="16" height="16"><![endif]-->

<p> more page... </p>

Lazy loading

Lazy loading aka post-loading• After-onload• Some images• Below the fold (on scroll)• Hidden content e.g. tabs

Amazon’s lazy bestsellers • Page’s purpose is ranking• Details can come later• via onload XHR• JS off = no details• but that’s fine (see bullet #1)

Lazy evaluation

GMail mobile’s lazy JS <!doctype html><html><body>...<script id="lazy">/*console.log("I can wait");*/</script>...<script>console.log("I'm needed");window.onload = function () { var comment = document.getElementById('lazy') .innerHTML, code = comment.substring(3, comment.length - 3); eval(code);};</script></body></html> http://googlecode.blogspot.com/2009/09/gmail

-for-mobile-html5-series-reducing.html

Lazy HTML<!doctype html><html><body>...<div id="lazy"><!--<p>lots of html goes here...</p>--></div>...<script>window.onload = function () { var el = document.getElementById('lazy'), inner = el.innerHTML, code = inner.substring(4, inner.length - 3); el.innerHTML = code;};</script></body></html>

http://phpied.com... (coming-soon)

Lazy HTML test• 500K (200K gzipped) HTML doc• “Sherlock Holmes”• comment out 95%• still one whole chapter left

http://www.phpied.com/files/lazyhtml/start.html

Lazy HTML test results

Lazy HTML - misc• Who loads a book?• Use case: blog comments• SEO? Content is hidden• What about display: none?• The test page was simple-to-render, no complex layout

Preloads

Preloads• Anticipate next page• Problems: - does next page anticipate you? - parsing and execution time• <link prefetch="http://..">

Preload sans executevar preload; if (/*@cc_on!@*/false) { // IE preload = function (file) { new Image().src = file; };} else { preload = function (file) { var obj = document.createElement('object'), body = document.body; obj.width = 0; obj.height = 0; obj.data = file; body.appendChild(obj); };}

Preload, then executevar loader = function (file, callback) { var obj = document.createElement('object'), body = document.body; obj.width = 0; obj.height = 0; obj.data = file; obj.onload = function () { var h, js = document.createElement('script'); js.src = file; js.onload = callback; h = document.getElementsByTagName('head')[0]; h.appendChild(js); }; body.appendChild(obj);};

Browser search preload

Chrome search• In-browser search box• Gives suggestions as you type• Visual suggestions in IE8+

IE8 Visual Search Suggestions

...<Item> <Text>Currently: Partly Cloudy, 67F</Text> <Description>High: 71F Low: 63F</Description> <Url>http://weather.yahoo.com/forecast/USCA1024_f.html</Url> <Image source="http://l.yimg.com/a/i/us/we/31/30.gif" alt="Partly Cloudy" width="31" height="31"/></Item>...

IE8 Visual Search Preload

...<Item> <Text>any search suggestion</Text> <Image source="http://path/to/sprite.png" width="0" height="0"/></Item>...

IE8 Visual Search Preload

IE8 Visual Search Preload

• didn’t work for CSS and JS

IE8 Visual Search

• preload images, e.g. sprite• DNS lookups via beacons

Parting words

Do care about• Progressive, non-blocking, asynchronous downloads• Progressive rendering

Thank you!

Stoyan Stefanov@stoyanstefanovhttp://www.phpied.comSlides: http://slideshare.net/stoyan/

top related