load_time > 6000 &&
Math.random() < .4 ?
fail() : profit()
while( wait_time % 500 )
(╯°□°)╯︵ ┻━┻
http://glinden.blogspot.com/2006/11/marissa-mayer-at-web-20.html
http://glinden.blogspot.com/2006/11/marissa-mayer-at-web-20.html
2015
2015
we’ve decided to take site speed into account in our search rankings
https://webmasters.googleblog.com/2010/04/using-site-speed-in-web-search-ranking.html
https://blog.cloudflare.com/ttfb-time-to-first-byte-considered-meaningles
how long it takes for a webpage to be loaded and usable by a browser
https://www.littlebizzy.com/blog/ttfb-meaningless
Performance
Perception
Performance
Perception
Delay | User reaction |
---|---|
0 - 100 ms | Instant |
100 - 300 ms | Feels sluggish |
300 - 1000 ms | Acceptable for changing views |
> 1 s | Mental context switch |
> 10 s | Frustrated, leave, may or may not return |
https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/rail
https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/rail
https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/rail
https://developers.google.com/web/fundamentals/performance/rendering/
https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/rail
https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/rail
Don't make it so pretty that it doesn't work for the end user
Devs must remember...
...what happens in the intermediate steps between receiving the HTML, CSS, and JavaScript bytes and the required processing to turn them into rendered pixels
load html > load resources > parse > display
https://developers.google.com/web/fundamentals/performance/critical-rendering-path
https://developers.google.com/web/fundamentals/performance/critical-rendering-path/analyzing-crp
https://developers.google.com/web/fundamentals/performance/critical-rendering-path/optimizing-critical-rendering-path
https://varvy.com/pagespeed/critical-render-path.html
https://css-tricks.com/fout-foit-foft
</body>
if it doesn't depend on script order
http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded
<div style="color:salmon">
require('juice')
require('inline-css')
critical.generate({
base: 'test/',
src: 'index.html',
dest: 'styles/styles.min.css',
minify: true,
width: 1300,
height: 900
});
https://github.com/addyosmani/critical
<picture>
<source media="(min-width: 40em)"
srcset="logo.large.png 1x, logo.large.2x.png 2x">
<source
srcset="logo.small.png 1x, logo.small.2x.png 2x">
<img src="logo.png" alt="DevLeague">
</picture>
https://responsiveimages.org
<img src="logo.small.png"
srcset="logo.large.png 1024w, logo.medium.png 640w, logo.small.png 320w"
sizes="(min-width: 36em) 33.3vw, 100vw"
alt="DevLeague">
https://responsiveimages.org
<picture class="intrinsic intrinsic--square">
<source media="(min-width: 500px)" srcset="logo.large.png">
<img class="intrinsic-item" srcset="logo.small.png" alt="">
</picture>
http://daverupert.com/2015/12/intrinsic-placeholders-with-picture
http://www.guypo.com/introducing-lqip-low-quality-image-placeholders/
<figure>
<div>
<div/> <!-- this div keeps the aspect ratio so the placeholder doesn't collapse -->
<img/> <!-- this is a tiny image with a resolution of e.g. ~27x17 and low quality -->
<canvas/> <!-- takes the above image and applies a blur filter -->
<img/> <!-- the large image to be displayed -->
<noscript/> <!-- fallback for no JS -->
</div>
</figure>
https://jmperezperez.com/medium-image-progressive-loading-placeholder/
https://code.facebook.com/posts/991252547593574/the-technology-behind-preview-photos/
this helped speed up profile and page loads by 30 percent
https://code.facebook.com/posts/991252547593574/the-technology-behind-preview-photos/
proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=backcache:8m max_size=50m;
proxy_cache_key "$scheme$request_method$host$request_uri$is_args$args";
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
location / {
proxy_cache backcache;
proxy_cache_bypass $http_cache_control;
add_header X-Proxy-Cache $upstream_cache_status;
...
if ( contentChanged )
respond.status(200).send(content);
else
respond.status(304);
https://varvy.com/ifmodified.html
http://www.html5rocks.com/en/tutorials/service-worker/introduction/
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(function(registration) {
console.log(
'ServiceWorker registered with scope: ',
registration.scope
);
}).catch(function(err) {
console.log(
'ServiceWorker registration failed: ',
err
);
});
}
chrome://inspect/#service-workers
var CACHE_NAME = 'my-app-cache-v1';
var urlsToCache = [
'/',
'/css/bundle.css',
'/js/bundle.js'
];
self.addEventListener('install', function(event) {
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
}
)
);
});
https://docs.google.com/presentation/d/1GNLc4oRZzazq4Th8vsH3v5GekAbKWsxIXHbNtQFFG-c/present
<img src="logo.png" />
<img src="logo.242.png" />
<img src="logo.png#20160831" />
gzip on;
gzip_min_length 1000;
gzip_proxied expired
no-cache
no-store
private
auth;
gzip_types text/plain
application/xml
application/json;
Accept-Encoding: gzip, deflate
Content-Encoding: gzip
# Enable Nginx HttpGzipStaticModule
server {
...
gzip_static on;
}
Accept-Encoding: gzip, deflate
Content-Encoding: gzip
uncompressed: 106,272 bytes
mod_deflate: 28,732 bytes (27%)
gzip -9: 28,062 bytes (26%)
Zopfli: 27,033 bytes (25%)
https://github.com/google/zopfli
http://www.cambus.net/serving-precompressed-content-with-nginx-and-zopfli/
https://www.stevesouders.com/blog/2013/03/08/zopflinator/
server {
...
brotli on;
brotli_static on;
brotli_types text/plain application/xml application/json;
}
Accept-Encoding: brotli
https://github.com/google/ngx_brotli
https://quixdb.github.io/squash-benchmark/
ngx_brotli filter module - on the fly
ngx_brotli static module - precompressed
comp level | comp speed | decomp speed |
---|---|---|
zlib deflate 4 | 21.45 MiB/s | 96.16 MiB/s |
zlib gzip 4 | 20.71 MiB/s | 89.21 MiB/s |
brotli 1 | 23.94 MiB/s | 115.02 MiB/s |
http://flif.info
https://www.devleague.com/css/bundle.css
origin
:443
https://www.devleague.com/css/bundle.css
https://www.devleague.com/js/bundle.js
https://www.devleague.com/images/asset1.png
https://www.devleague.com/images/asset2.png
https://www.devleague.com/images/asset3.png
https://www.devleague.com/images/asset4.png
https://www.devleague.com/images/asset5.png
https://www.devleague.com/images/asset6.png
https://www.devleague.com/images/asset7.png
https://www.devleague.com/images/asset8.png
https://www.devleague.com/images/asset9.png
https://www.devleague.com/images/asset10.png
https://www.devleague.com/images/asset11.png
https://www.devleague.com/images/asset12.png
https://www.devleague.com/images/asset13.png
https://www.devleague.com/images/asset14.png
https://www.devleague.com/images/asset15.png
https://www.devleague.com/images/asset16.png
Waiting...
Loading...
https://cdn1.devleague.com/css/bundle.css
origin
:443
https://cdn1.devleague.com/css/bundle.css
https://cdn1.devleague.com/js/bundle.js
https://cdn1.devleague.com/images/asset1.png
https://cdn1.devleague.com/images/asset2.png
https://cdn1.devleague.com/images/asset3.png
https://cdn1.devleague.com/images/asset4.png
https://cdn2.devleague.com/images/asset5.png
https://cdn2.devleague.com/images/asset6.png
https://cdn2.devleague.com/images/asset7.png
https://cdn2.devleague.com/images/asset8.png
https://cdn2.devleague.com/images/asset9.png
https://cdn2.devleague.com/images/asset10.png
https://cdn3.devleague.com/images/asset11.png
https://cdn3.devleague.com/images/asset12.png
https://cdn3.devleague.com/images/asset13.png
https://cdn3.devleague.com/images/asset14.png
https://cdn3.devleague.com/images/asset15.png
https://cdn3.devleague.com/images/asset16.png
Loading...
Loading...
Loading...
page load performance decrease 5x
https://facebook.github.io/react/docs/environments.html
const React = require('react');
const ReactDOMServer = require('react-dom/server');
...
app.get('/', (req, res) => {
const element = React.createElement('div', null, 'Hello World!');
res.send(ReactDOMServer.renderToString(element));
});
function ngApp(req, res) {
let baseUrl = '/';
let url = req.originalUrl || '/';
let config: ExpressEngineConfig = {
directives: [ App ],
platformProviders: [
{provide: ORIGIN_URL, useValue: 'http://localhost:3000'},
{provide: BASE_URL, useValue: baseUrl},
],
providers: [
{provide: REQUEST_URL, useValue: url},
provideRouter(routes),
NODE_LOCATION_PROVIDERS,
NODE_HTTP_PROVIDERS,
],
async: true,
preboot: false
};
res.render('index', config);
}
app.get('/', ngApp);
app.get('/home', ngApp);
app.get('/about', ngApp);
https://universal.angular.io
https://universal.angular.io
facebook, twitter, etc.
setTimeout( doSomeHeavyLifting, 0);
releases control from the main thread
pushes it to the end
var worker = new Worker(‘heavy.js’);
worker.addEventListener(‘message’, workDone);
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
for designers and developers
<link rel="prefetch" href="hero.2x.jpg">
<link rel="prerender" href="http://www.devleague.com">
<link rel="dns-prefetch" href="//devleague.com">
https://css-tricks.com/prefetching-preloading-prebrowsing/
https://www.stevesouders.com/blog/2013/11/07/prebrowsing/
<!doctype html>
<html ⚡>
<head>
<meta charset="utf-8">
<link rel="canonical" href="hello-world.html" >
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<style amp-boilerplate>
body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;...
</style>
<noscript><style amp-boilerplate>
body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}
</style></noscript>
<script async src="https://cdn.ampproject.org/v0.js"></script>
</head>
<body>Hello World!</body>
</html>
https://www.ampproject.org
Link: </css/style.css>; rel=preload;
https://www.cloudflare.com/http2/server-push
~70k budget, ATF
https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index