Сергей Перескоков, Яндекс.Еда
Время | Что видит юзер |
---|---|
0-16мс | Время на отрисовку кадра |
0-100мс | Мгновенный отклик |
100-300мс | Заметная задержка |
300-1000мс | Выполнение задачи |
> 1000мс | Теряется фокус внимания |
Первая отрисовка полезного контента для пользователя
HTTP ответ в браузер может прилетать по частям
app.get('/', async (req, res) => {
res.write(`
<html>
<head>
<script src='...'>
<link rel='stylesheet'>
`)
// TTFB here
// Start loading scripts/fonts/stylesheets
const data = await heavyRequest(...)
res.write(`
<title>...</title>
</head>
<body>
${dataToHTML(data)}
</body>
</html>
`)
res.end()
})
import zlib, {Gzip} from 'zlib'
app.get('/', async (req, res) => {
const stream = zlib.createGzip()
// Отключаем буферизацию для proxy_pass
res.setHeader('X-Accel-Buffering', 'no')
stream.pipe(res)
stream.write(`
<html>
<head>
...
`)
// Отправляем содержимое всего стрима в HTTP ответ
stream.flush()
const data = await heavyRequest(...)
stream.write(`
<title>...</title>
</head>
<body>
...
</body>
</html>
`)
stream.flush()
stream.end()
})
import zlib, {Gzip} from 'zlib'
app.get('/', async (req, res) => {
const stream = zlib.createGzip()
stream.pipe(res)
stream.write(`
<html>
<head>
<script src="..."></script>
<div id="splash-screen"></div>
`)
...
})
(Плохой вариант)
import zlib, {Gzip} from 'zlib'
app.get('/', async (req, res) => {
const stream = zlib.createGzip()
stream.pipe(res)
stream.write(`
<html>
<head>
<script src="..."></script>
<script>
document.write('<body' + '><' + 'div id="splash-screen"><' + '/div>');
</script>
`)
...
})
Момент, когда пользователь может что-то делать со страницей
Скрывайте то, что не видно
render = () => (
<InView>
{
({inView}) => {
if (inView) {
return (
<Content />
)
}
return (
<Skeleton />
)
}}
</InView>
)
Q: А если сразу нужно отрисовать много контента?
A: Отрисовываем, замеряем, удаляем лишнее
Загружайте только то, что нужно
Рендерите, что видно
Посматривайте периодически в Lighthouse (CI)
Изучите вашу аудиторию перед началом оптимизации
Не забывайте про прогресс
Сергей Перескоков, Яндекс.Еда