Артём Кувалдин, Роман Парадеев
Ускорение сайта уменьшает расходы на бэкенд.
Производительность влияет на поведение пользователей
Поисковые движки учитывают скорость сайта при ранжировании.
Мобильных пользователей уже больше, чем десктопных
var performance = window.performance ||
window.webkitPerformance ||
window.msPerformance ||
window.mozPerformance;
console.log(performance.timing);
connectEnd: 1460572234112
connectStart: 1460572234112
domComplete: 1460572255927
...
RTT + Backend
↕
DNS → TCP → Request → Waiting → Response → Render
↑ ↓
↑ ← ← ← ← ← ← ← Resources
Bytes/Characters/Tokens/Nodes
↓
DOM → B/C/T/N → CSSOM
↓ ↓
Render Tree
↓
Paint
Про сеть – HTTP и REST. Сергей Гоголев
Про браузер – Браузер. Олег Мохов
Про картинки – Графика. Кувалдин Артем
> svgo -f static/img/emoji/svg
Processing directory 'static/img/emoji/svg':
amused-black-face-with-closed-eyes-and-mouth.svg:
Done in 56 ms!
1.12 KiB - 53.4% = 0.522 KiB
amused-black-solid-emoticon-face-for-interface.svg:
Done in 21 ms!
1.122 KiB - 53.5% = 0.521 KiB
# собираем все векторные иконки в один файл
> cat static/img/emoji/svg/* > static/img/emoji/svg/_bundle.svg
# итоговый размер векторных иконок
> du -h static/img/emoji/svg/_bundle.svg
48K static/img/emoji/svg/_bundle.svg
# исходный расмер растровых иконок
> du -h static/img/emoji/png
544K static/img/emoji/png
<section class="emoji-list">
<img src="img/emoji/png/amused-black-face-with-closed-eyes-and-mouth.png">
<img src="img/emoji/png/amused-black-solid-emoticon-face-for-interface.png">
<img src="img/emoji/png/amused-smiling-black-emoticon-face.png">
<img src="img/emoji/png/angry-black-emoticon-face.png">
<img src="img/emoji/png/angry-black-face-1.png">
<img src="img/emoji/png/angry-black-face.png">
<section class="emoji-list">
<svg xmlns="http://www.w3.org/2000/svg" width="478.125" height="478.125" viewBox="0 0 478.125 478.125">
<path d="M239.062 0C107.1 0 0 107.1 0 239.062c0 131.963 107.1 239.062 239.062 239.062 131.963 0 239.062-107.1 239.062-239.062C478.125 107.1 371.025 0 239.062 0zM116.663 175.95l63.112-42.075 11.475 15.3-65.025 42.075-9.562-15.3zm122.399 187.425C172.125 363.375 153 306 153 306s28.688 19.125 86.062 19.125S325.125 306 325.125 306 306 363.375 239.062 363.375zM351.9 191.25l-63.113-42.075 11.476-15.3 63.112 42.075-11.475 15.3z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="478.125" height="478.125" viewBox="0 0 478.125 478.125">
<path d="M239.062 0C107.1 0 0 107.1 0 239.062c0 131.963 107.1 239.062 239.062 239.062 131.963 0 239.062-107.1 239.062-239.062C478.125 107.1 371.025 0 239.062 0zM126.225 133.875l63.112 42.075-9.562 15.3-63.112-42.075 9.562-15.3zm112.837 229.5C172.125 363.375 153 306 153 306s28.688 19.125 86.062 19.125S325.125 306 325.125 306 306 363.375 239.062 363.375zM298.35 191.25l-11.475-15.3 63.112-42.075 11.476 15.3-63.113 42.075z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="478.125" height="478.125" viewBox="0 0 478.125 478.125">
<path d="M239.062 0C107.1 0 0 107.1 0 239.062c0 131.963 107.1 239.062 239.062 239.062 131.963 0 239.062-107.1 239.062-239.062C478.125 107.1 371.025 0 239.062 0zM114.75 172.125h76.5v19.125h-76.5v-19.125zm124.312 191.25C172.125 363.375 153 306 153 306s28.688 19.125 86.062 19.125S325.125 306 325.125 306 306 363.375 239.062 363.375zM363.375 191.25h-76.5v-19.125h76.5v19.125z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="478.125" height="478.125" viewBox="0 0 478.125 478.125">
<path d="M239.062 0C107.1 0 0 107.1 0 239.062c0 131.963 107.1 239.062 239.062 239.062 131.963 0 239.062-107.1 239.062-239.062C478.125 107.1 371.025 0 239.062 0zm93.713 114.75l11.475 15.3-65.025 42.075-11.475-15.3 65.025-42.075zm-187.425 0l63.112 42.075-9.562 15.3-63.112-42.075 9.562-15.3zm-11.475 76.5c0-11.475 7.65-19.125 19.125-19.125s19.125 7.65 19.125 19.125-7.65 19.125-19.125 19.125-19.125-7.65-19.125-19.125zm105.187 153c-57.375 0-86.062 19.125-86.062 19.125S172.125 306 239.062 306s86.062 57.375 86.062 57.375-28.686-19.125-86.062-19.125zm86.063-133.875c-11.475 0-19.125-7.65-19.125-19.125s7.65-19.125 19.125-19.125 19.125 7.65 19.125 19.125-7.65 19.125-19.125 19.125z"/></svg>
> du -h static/img/cats
2,9M static/img/cats
# уменьшаем размер с помощью imagemagick
> mogrify -resize 600 static/img/cats/*.jpg
# вырезаем exif и конвертируем в pregressive
> imagemin --progressive static/img/cats/* static/img/cats
> du -h static/img/cats
260K static/img/cats
<script src="vendor/jquery/dist/jquery.js"></script>
- <script src="vendor/jqueryui-browser/ui/jquery-ui.js"></script>
<link rel="stylesheet" href="vendor/bootstrap/dist/css/bootstrap.css">
- <script src="vendor/bootstrap/dist/js/bootstrap.js"></script>
<script src="js/main.js"></script>
<link rel="stylesheet" href="css/style.css">
<head>
<link rel="stylesheet" href="vendor/bootstrap/dist/css/bootstrap.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<script src="vendor/jquery/dist/jquery.js"></script>
<script src="vendor/timing.js/timing.js"></script>
<script src="js/main.js"></script>
</body>
> uncss http://localhost:8080/showcase > static/css/bundle.css
# исходный размер одного библиотечного файла
> du -h node_modules/bootstrap/dist/css/bootstrap.css
144K node_modules/bootstrap/dist/css/bootstrap.css
# итоговый размер всей сборки целиком
> du -h static/css/bundle.css
4,0K static/css/bundle.css
<img data-src="img/cats/angry.jpg">
<img data-src="img/cats/hangover.jpg">
<img data-src="img/cats/wise.jpg">
window.onload = function () {
$('img').each(function () {
var $img = $(this);
$img.attr('src', $img.data('src'));
});
};
// включаем GZIP
app.use(require('compression')());
// включаем кэширование на 30 дней
app.use(express.static('static', {
maxAge: 1000 * 60 * 60 * 24 * 30
}));
Уменьшайте количество запросов
Оптимизируйте контент
Используйте GZIP
Настройте кэширование
Используйте CDN
setInterval(writeRandomFibonacciNumber, 10 * 1000);
function writeRandomFibonacciNumber() {
var number = getRandomInt(35, 42);
var result = fib(number);
console.log('Fib(' + number + ') = ' + result);
}
function fib(n) {
if (n === 0) return 0;
if (n === 1) return 1;
return fib(n - 2) + fib(n - 1);
}
// worker.js
onmessage = function (event) {
var number = event.data;
var result = fib(number);
postMessage([number, result]);
}
function fib(n) {
if (n === 0) return 0;
if (n === 1) return 1;
return fib(n - 2) + fib(n - 1);
}
// main.js
var myWorker = new Worker("js/worker.js");
setInterval(function () {
var number = getRandomInt(35, 42);
worker.postMessage(number);
}, 10 * 1000);
myWorker.onmessage = function (event) {
var number = event.data[0]
var result = event.data[1];
console.log('Fib(' + number + ') = ' + result);
}
Размер страницы: 4 MB → 300 KB
Время загрузки: 22 s → 1 s
Уменьшайте количество запросов
Оптимизируйте контент
Используйте GZIP
Настройте кэширование
Используйте CDN