one request per page
node streams, gzip, http connections, and you.
I'm JAKE SCOTT
Software engineer at
(we're hiring!)
make the web faster?
- increase conversions
- decrease server load
- increase revenue
Make the web faster.
- decrease payload size
- reduce request overhead
- make the load feel shorter
gzip - decrease payload size
- replaces duplicated symbols with pointers
- maximum window of 32kB
- maximum symbol size of 258B
Reduce request overhead
Every* request will have these:
-
referral URL
- resource URL
- cookies
These headers add up.
The less requests you make, the better.
How do I reduce requests?
- concatenate js files
- concatenate css files
- concatenate image files?
Apparent load times
What the user doesn't know won't bug them.
Avoid the white screen of death.
decrease (apparent) load time
above the fold (ATF) matters
- inline ATF CSS
- ATF HTML should come first
- what about images?
Images, images, images
Current solutions:
- CSS sprite sheets
- refactor your whole page
- maintaining sucks
- Data URIs
- 33% bloat (binary -> base64 utf-8)
A new solution for images
- easy to implement
- easy to maintain
- stream everything
- respond instantly
- reduce requests
- load ATF first
Finally, some node
this is wan.js
Wan.js
Turns all your <img> tags into one
streaming, compressed, prioritized,
progressive, cached request.
- koa middleware
- express middleware
- small client side file
How its used
- replace <img src="...">
with <img data-src="..."> - optionally set priority attribute
- call Wan.getImages();
How it works (server)
- request all image URLs at once
- stream images 1 by 1, base64 encoded
- pipe stream to gzip
- pipe stream to http.serverResponse
res.setHeader('Transfer-Encoding', 'chunked');
res.setHeader('Content-type', 'text/html; charset=utf-8');
HOW IT WORKS (SERVER)
Request is processed as a stream
HOW IT WORKS (SERVER)
- stream file names from request
- write cached content to responseORpipe file stream to response
-
cache contents of file after stream ends
-
take the next file name from request stream
...probably should have been written as a transform stream
file names → cache/read stream → response
STream file names from req
Process file names as they come in.../imgs/lolcat.jpg&
/imgs/memes/crazy-guy.jpg&
/omg.png&/icons.png&/icons2.png&
/assets/other/mountain.jpg&
/some/partially/transferred/filena
...buffer the ones that are not complete
TRANSFORM FILE NAME TO CONTENT
- internal cache returns file content as string, read
stream if not cached, or undefined if ENOENT - cache fills itself from read stream
- partial caching if stream isn't done
if(!asset) {
done();
}
else if(typeof asset === 'string') { res.write(asset);
done();
}
else {
asset.on('error', function () {...}).on('end', done);
res.pipe(asset, {end: false})
}
HOW IT WORKS (CLIENT)
- get all <img> tags with data-src
attributes
- remove data-src attribute
- sort unique URLs by priority attribute
- make GET if possible, POST otherwise
-
stream in response, setting data URI
Currently, it's a bit GC hungry.if(xhr.readyState == 3) {
var relevant = xhr.responseText.substring(parserIndex)
, parts = relevant.split('\n')
, part;
//...
}
HOW IT WORKS (CLIENT)
-
cache in memory
-
cache in local storage
-
GETs use normal cache
- uses cache control header to dictate behavior
- each file cached separately
Gzip... image streams?
- redundant headers for small images
- base64 + gzip < binary (usually)
charts from http://davidbcalhoun.com/
RESULT (SMITHSONIAN.COM)
After:
38 images
0.1MB smaller payload*
*...Not sure if chrome is reporting header content here
ADvantages over Css Sprites
- full control over image priority
- easy to convert src to data-src
- no build step
- no maintenance
- possibly smaller! (but not likely)
DISadvantages
- Can't use progressive JPGs
- POSTs won't cache, relies on local storage
- Slower on lossy connections
- Does not yet work in IE (go figure)
QUESTIONS?
GITHUB: https://github.com/mako-taco/wan
one request per page
By Jake Scott
one request per page
- 1,141