Перед вами быстрый, удобный и отзывчивый сайт? Возможно, это не результат плодотворной работы множества людей, а всего лишь набор психологических и инженерных трюков, направленных на улучшение Perceived Performance.
В большинстве случаев с ростом реальной производительности улучшается и Perceived Performance. А когда реальная производительность не может быть с легкостью увеличена, существует возможность поднять видимую. В своем докладе на Frontend Live 2020 бывший разработчик Avito Frontend Architecture Алексей Охрименко рассказал о приемах, которые улучшают ощущение скорости там, где ускорить уже нельзя.
Производительность — обязательное условие успеха современных Web-приложений. Есть множество исследований от Amazon и Google, которые говорят, что понижение производительности прямо пропорционально потере денег и ведет к слабой удовлетворенности вашими сервисами (что снова заставляет терять деньги).
Первопричина полученного стресса — ожидание. Научно доказано, что оно может вызывать:
беспокойство;
неуверенность;
дискомфорт;
раздражение;
скуку.
Вряд ли кто-то хочет, чтобы пользователи испытывали эти эмоции. Поэтому так важно уменьшать время ожидания.
Самое простое решение — все делать быстро. Но прежде, чем вы скажете: «Спасибо, капитан!», хочу напомнить, что увеличение производительности ведет к прямому уменьшению времени ожидания.
Не игнорируйте этот момент: вы обязательно должны его учитывать.
Для этого есть множество разнообразных техник, в том числе:
lighthouse;
devTools profiler.
Но даже если все сделать идеально, этого может оказаться недостаточно.
Есть интересная история про аэропорт Houston. Она отлично вписывается и в современные реалии разработчиков.
Существует некий сценарий использования аэропорта: самолет прилетает, высаживает пассажиров, выгружает багаж. Пассажиры идут в зону выдачи, чемоданы через какое-то время появляются на транспортере.
Люди часто жаловались на долгое ожидание багажа в аэропорту. И инженеры аэропорта Huston не спали ночами, работали сверхурочно, но реализовали выдачу багажа всего за 8 минут. Однако клиенты все равно продолжали жаловаться.
Инженеры не знали, что делать. И они решили попробовать один трюк. Высадив людей как можно дальше от зоны выдачи багажа, они вынудили их быть в активном ожидании. Пока те добирались до места назначения, багаж уже ждал их. В результате все жалобы прекратились. Но самое интересное, что реальное время выдачи багажа осталось абсолютно таким же: 8 минут.
Почему же клиенты пришли в восторг от происходящего, хотя реальная производительность никак не изменилась?
Perceived Performance
Инженеры аэропорта улучшили Perceived Performance, или видимую производительность. Это очень глубокий термин. Видимая производительность включает в себя реальную производительность.
Если вы ускорите работу своего сайта, увидите, что он ускорился — абсолютно логичная закономерность.
Применяя разнообразные психологические трюки, грамотно проектируя свое приложение и используя умные алгоритмы приоритезации, мы можем добиться увеличения только видимой производительности. Реальная производительность при этом не изменится, но пользователь будет воспринимать произошедшее как улучшение, ускорение производительности сайта.
Все это базируется на том, что люди не очень хорошо умеют измерять реальную производительность. И именно эту особенность можно эксплуатировать.
Все дальнейшие примеры будут для Angular приложений, но, несмотря на это, они применимы к любому современному фреймворку. Приступим!
Не блокируйте пользователя
Первый совет: ни в коем случае не стоит блокировать пользователя. Вы можете сейчас сказать: «Я и не блокирую!».
Попробуйте узнать себя в этом примере:
Допустим, мы кликаем на удаление какого-то элемента, запрашиваем данные, после чего удаляем.
Все равно не узнаете? А так?
Спиннеры — это не выход! Хоть они и могут стать ленивым способом разобраться с неудобной ситуацией.
Что можно предложить в качестве альтернативы спиннеру?
Можно нажать на кнопку «Удалить» и показать статус этой кнопки (item удаляется только для одного элемента), не демонстрируя спиннер. В дальнейшем можно отправить запрос на сервер, и когда он придет, показать, что элемент удалился, либо — при ошибке — передать данные о ней. Вы можете возразить: «Но я могу делать только 1 запрос за раз!» — это ограничение бэкенда. С помощью RxJs и оператора concat можно буквально одной строчкой кода создать минимальную очередь:
import { concat } from 'rxjs';
const source = concat(
myService.saveStuff({ test: 'swag '}),
myService.saveStuff({ test: 'yolo '})
);
Более серьезная имплементация, конечно, займет больше, чем одну строчку.
Вы можете сказать: «Я не могу не блокировать компонент потому, что он состоит из какой-то логики. То есть существуют набор элементов и действия, которые я не могу совершать».
Но ничто вам не мешает не показывать спиннер на весь экран, а поместить его только в той области, которая должна быть заблокирована по факту:
<ngx-spinner [fullScreen]="false">
<p class="loading">Loading Awesomeness...</p>
</ngx-spinner>
В Angular есть ngx-spinner, который поддерживает такой функционал.
Это, как минимум, уменьшит время ожидания, и пользователь сможет в этот момент сделать хоть что-то.
Обманывайте
Обман зачастую базируется на иллюзиях скорости.
Допустим, есть два спиннера с точками. Если увеличить количество точек в одном из них, кажется, что он начинает крутиться быстрее. На самом деле скорость спиннеров одинакова.
Иллюзия базируется на простом эффекте: чем больше точек, тем больше Motion Blur (размытие движения). Этот трюк используется в мультфильмах. Возможно, вы видели, что когда койот бежит очень быстро, у него размываются ноги, и вместо них появляется облако.
Где можно применить такую "иллюзию"?
Progress Bar;
Есть исследование, показывающее, что если добавить полоски, которые идут в обратном направлении внутри Progress Bar, то визуально он выглядит как более быстрый. В такой настройке можно получить до 12% ускорения, просто применив дополнительный скин. И пользователи воспримут работу, прошедшую под этим Progress Bar, на 12% быстрее. Вот пример того, как можно реализовать такой слайдер на CSS.
Скелетон;
Если спиннеры — это плохо, что же тогда показать на экране? Можно продемонстрировать силуэт, некий образ того контента, который будет отображен.
Скелетон — это некое схематическое отображение сайта до момента его загрузки:
В этом примере мы видим, где будут расположены чаты.
Существует исследование, которое показывает, что люди воспринимают скелетоны быстрее от 10 до 20%.
То есть по ощущениям пользователей, сайты со скелетоном работают быстрее.
Существует огромное количество нужных компонентов для Angular, React, View. К примеру, для Angular есть ngx-skeleton-loader, в котором можно прописать внешний вид и сконфигурировать его. После чего мы получим наш скелетон:
<ngx-skeleton-loader
appearance="circle"
[theme]="{ width: '80px', height: '80px' }"
>
</ngx-skeleton-loader>
Будьте оптимистами
Помните CS:GO? Вы забежали за стену и вас убивают! Это наверняка читеры, вы же были за стеной! На самом деле это Latency/Lag compensation.
В мире frontend это называется Optimistic Updates. Самый яркий пример это Twitter
Клик отрабатывает моментально, при этом мы видим что запрос на backend отработал только через 2 секунды.
Как реализовать Optimistic Updates у себя? Давайте рассмотрим самый простой пример http запроса:
addItem(item) {
return this.http.post<Item>('/add-item', item)
.subscribe(res => {
this.items.push(res);
}, error => {
this.showErrorMessage(error);
})
}
Теперь применим к нему Optimistic Update:
addItem(item) {
this.items.push(item); // делаем заранее
return this.http.post<Item>('/add-item', item)
.subscribe(
res => {
// ничего не делаем в случае успеха
}, error => {
// в случае ошибки - откатываем состояние
this.items.splice(this.items.indexOf(item), 1);
this.showErrorMessage(error);
}
);
}
Для State Managers все немного сложнее, но для каждого есть своя реализация и свои паттерны для реализации Optimistic Updates. В этой статье я не буду приводить примеры, их легко можно найти под подходящий State Manager (redux, mobx, appollo-graphql, etc.)
Экспоненциальная выдержка
Следующее, что необходимо проявлять — это не обычную выдержку, а экспоненциальную. Optimistic Updates имеют одну проблему: мы обязаны откатить состояния приложения назад в случае наличия проблемы с запросом и показать сообщение об ошибке. Но эту ситуацию можно сгладить. Давайте посмотрим на простой пример с Optimistic Update:
addItem(item) {
return this.http.post<Item>('/add-item', item)
.subscribe(res => {
this.items.push(res);
}, error => {
this.showErrorMessage(error);
})
}
Мы можем сделать так, что API будет выглядеть более стабильным за счет одной простой функции. Получив ошибку на запрос, просто повторяем его.
addItem(item) {
this.items.push(item); // делаем заранее
return this.http.post<Item>('/add-item', item)
.pipe(retry()) // повторяем запрос
.subscribe(
// ...
);
}
Это одна из best practice в энтерпрайз-приложениях, потому что бэкенд может не работать по разным причинам. Например, происходит деплой или хитрая маршрутизация. В любом случае очень хорошее решение: попробовать повторить. Ведь никакое API не дает 100% гарантии, 99,9% uptime.
Но есть маленький нюанс. Если мы будем повторять бесконечно, то в какой-то момент повалим наш сервер. Поэтому обязательно поставьте ограничение. Например, повторять максимум 3 раза.
addItem(item) {
this.items.push(item); // делаем заранее
return this.http.post<Item>('/add-item', item)
.pipe(
retry(3)
)
.subscribe(
// ...
);
}
Но даже с этим сценарием мы сами себе можем сделать DDOS (Distributed Denial of Service). На это попадались многие компании. Например, Apple с запуском своего сервиса MobileMe.
В чем идея? Представьте на секунду, что ваш сервис падает под нагрузкой, то есть он с ней не справляется. Если сервер перегружен, то скорее всего ответит статус-кодом 500. Если вы попробуете еще раз, возможно, следующий запрос получит ответ.
Но если сервер упал под нагрузкой, и у всех одновременно запросы ответили с ошибкой, то все начнут перезапрашивать в одно и то же время, вы сами устроите себе DDOS. На сервер будет идти постоянная нагрузка, он не сможет передохнуть и наконец-то начать отвечать нормально.
Best practice: применять exponential backoff. В rxjs есть хороший дополнительный npm пакет backoff-rxjs, который за вас имплементирует данный паттерн.
import { retryBackoff } from 'backoff-rxjs';
addItem(item) {
this.items.push(item);
return this.http.post<Item>('/add-item', item)
.pipe(
retryBackoff({
initialInterval: 100,
maxRetries: 3,
resetOnSuccess: true
})
)
.subscribe(
// ...
);
}
Имплементация очень простая, 10 строчек кода. Здесь вы можете обойтись одной. Указываете интервал, через который начнутся повторы, количество попыток, и сбрасывать ли увеличивающийся таймер. То есть вы увеличиваете по экспоненте каждую следующую попытку: первую делаете через 1 с, следующую через 2 с, потом через 4 с и т.д.
Играя с этими настройками, вы можете настраивать их под ваше API.
Следующий совет очень простой — добавить Math.random() для initialInterval:
import { retryBackoff } from 'backoff-rxjs';
addItem(item) {
this.items.push(item);
return this.http.post<Item>('/add-item', item)
.pipe(
retryBackoff({
initialInterval: Math.random() * 100,
maxRetries: 3,
resetOnSuccess: true
})
)
.subscribe(
// ...
);
}
Идея в том, что изначально, если все одновременно начнут повторять запросы, все равно может возникнуть ситуация, когда появится огромное количество запросов одномоментно. Поэтому добавив некий рандомный запрос, вы как бы размажете нагрузку повторных запросов на бэкенд.
Предугадывайте!
Как уменьшить ожидание, когда невозможно ускорить процесс?
Вы можете просто делать все заранее. К примеру, если вы занимаетесь изготовлением мороженого и знаете, что оно готовится очень долго, можете сделать его заранее, поставить в холодильник и избежать огромной очереди. Этот прием можно применить в сценариях с веб-производительностью.
Предзагрузка картинок;
Один из самых простых примеров — это предзагрузка картинок. К примеру, у вас есть SPA-приложение. Вы открываете одну страничку, а на следующей есть набор иконок. Вы можете очень простым скриптом написать preload и загружать на конкретной странице картинки, необходимые для другой:
var images = [];
function preload() {
for (var i = 0; i < arguments.length; i++) {
images[i] = new Image();
images[i].src = preload.arguments[i];
}
}
preload(
"http://domain.tld/image-001.jpg",
"http://domain.tld/image-002.jpg",
"http://domain.tld/image-003.jpg"
)
Этот способ слишком «олдскульный», потому что есть предзагрузка для взрослых.
Предзагрузка 18+
Наверняка вы сталкивались в HTML со стеком link, который позволяет переподключить stylesheets:
<link
rel="stylesheet"
href="styles/main.css"
>
Немного поменяв атрибуты, мы можем применить его для предзагрузки:
<link
rel="preload"
href="styles/main.css"
as="style"
>
Можно указать атрибут rel ="preload", сослаться в ссылке на наш элемент (href="styles/main.css"), и в атрибуте as описать тип предзагружаемого контента.
prefetch.
Еще один вариант — это prefetch:
<link
rel="prefetch"
href="styles/main.css"
>
Главное — запомнить, что preload и prefetch — два самых полезных инструмента. Отличие preload от prefetch в том, что preload заставляет браузер делать запрос, принуждает его. Обычно это имеет смысл, если вы предзагружаете ресурс на текущей странице, к примеру, hero images (большую картинку).
ОК, это уже лучше, но есть одна маленькая проблема.
Если взять какой-нибудь среднестатистический сайт и начать префетчить все JavaScript модули, то средний рост по больнице составляет 3 МБ. Если мы будем префетчить только то, что видим на странице, получаем примерно половину — 1,2 МБ. Ситуация получше, но все равно не очень.
Что же делать?
Давайте добавим Machine Learning
Сделать это можно с помощью библиотеки Guess.js. Она создана разработчиками Google и интегрирована с Google Analytics.
Анализируя паттерны поведения пользователей и, подключаясь к вашему приложению и системе сборки, она может интеллектуально делать prefetch только 7% на странице.
При этом эта библиотека будет точна на 90%. Загрузив всего 7%, она угадает желания 90% пользователей. В результате вы выигрываете и от prefetching/preloading, и от того, что не загружаете все подряд. Guess.js — это идеальный баланс.
Сейчас Guess.js работает из коробки с Angular, Nuxt js, Next.js и Gatsby. Подключение очень легкое.
Поговорим о Click-ах
Что еще можно сделать, чтобы уменьшить ожидание?
<div (сlick)="onClick()">
Это button! Привет Вадим ;)
</div>
Как предугадать, на что кликнет пользователь? Есть очевидный ответ.
У нас есть событие, которое называется mousedown. Оно срабатывает в среднем на 100-200 мс раньше, чем событие Click.
Применяется очень просто:
<div (onmousedown)="onClick()">
Это button! Привет Вадим ;)
</div>
Просто поменяв click на mousedown, мы можем выиграть 100-200 мс.
Очень важное замечание (спасибо RouR что обратил внимание на это), На mousedown вы можете только начать скачивать ресурсы следующей страницы, предзагружать контент, в общем выполнять любую подготовительную работу и только после события click — «визуально» выполнять действие (выполнять переход, обрисовывать элементы)
Если вы будете выполнять действие на mousedown или hover - вы сломаете не только UX но и Accessibility. Будьте осторожны
Но мы можем заранее предсказать, что пользователь кликнет на ссылку, еще до того как сработает не только mousedown но и hover :)
Я пытаюсь кликнуть на ссылку, и сайт мне говорит, что он знал об этом на 240-500 мс раньше того, как я это сделал o_O.
Опять магия ML? Нет. Существует паттерн: когда мы хотим на что-то кликнуть, мы замедляем движение (чтобы было легче попасть мышкой на нужный элемент).
Есть библиотека, которая анализирует с какой скоростью замедляется движение мыши, и благодаря этому может предсказать, куда я кликну.
Библиотека называется futurelink. Ее можно использовать абсолютно с любым фреймворком:
var futurelink = require('futurelink');
futurelink({
links: document.querySelectorAll('a'),
future: function (link) {
// `link` is probably going to be clicked soon
// Preload everything you can!
}
});
Вы передаете ей те DOM элементы, которые должны участвовать в прогнозе. Как только библиотека предсказывает нажатие на элемент, сработает callback. Вы можете его обработать и начать загружать страницу или залогинить пользователя заранее.
Что пользователь хочет получить при переходе на страницу? В большинстве сценариев: HTML, CSS и немного картинок.
Все это можно реализовать за счет серверного рендеринга SSR.
В Angular для этого достаточно добавить одну команду:
ng add @nguniversal/express-engine
В большинстве случаев это работает замечательно, и у вас появится Server-Side Rendering.
Но что, если вы не на Angular? Или у вас большой проект, и вы понимаете, что внедрение серверного рендеринга потребует довольно большого количества усилий?
Здесь можно воспользоваться статическим prerender: отрендерить страницы заранее, превратить их в HTML. Для этого есть классный плагин для webpack, который называется PrerenderSPAPlugin:
const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
module.exports = {
plugins: [
...
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'),
routes: [ '/', '/about', '/some/deep/nested/route' ],
})
]
}
В нем нужно указываете директорию, куда вы хотите сохранять пререндеренные urls, и перечислить те, для которых нужно отрендерить контент заранее.
Но вы можете сделать все еще проще: зайти в свое SPA приложение и написать:
document.documentElement.outerHTML
получить пререндеренный HTML и воспользоваться им: сохранить это в файл. И вот у вас за пару минут появилась пререндеренная страница. Если ваша страница меняется очень редко, это неплохой вариант (как бы глупо он ни выглядел).
Заключение
Несмотря на то что Perceived Performance — очень субъективная метрика, ее можно и нужно измерять. Об этом говорилось в докладе Виктора Русаковича на FrontendConf 2019.
Он рассказывал о том, что в Скелетоне есть анимация в плавном фоне, и слева направо она воспринимается на 68% быстрее, чем справа налево. Есть разные исследования, которые показывают, что неправильно примененные техники Perceived Performance могут визуально сделать сайт хуже. Поэтому обязательно тестируйте.
Сделать это можно при помощи сервиса под названием Яндекс.Толока.
Он позволяет выбирать, какой из двух объектов лучше. Можно сделать два видео с разной анимацией и предложить пользователям оценить, какой из них быстрее. Это стоит недорого, скейлится очень хорошо. В сервисе зарегистрировано огромное количество людей из разных регионов, то есть можно делать разнообразные выборки по разным параметрам. Благодаря этому есть возможность провести серьезное UX-исследование за небольшую сумму.
Даже если в конце концов вашему начальнику покажется, что быстрее не стало, проведите исследование и попробуйте улучшить ситуацию с помощью Perceived Performance.
Perceived performance — это низковисящий фрукт почти в любой компании. Именно сейчас у вас есть возможность, применив вышеперечисленные техники, улучшить воспринимаемую производительность и сделать пользователей и менеджеров счастливыми.
Подписывайтесь на Telegram канал obenjiro_notes и Twitter obenjiro.
Хотите стать спикером FrontendConf 2021? Если вам есть что сказать, вы хотите подискутировать или поделиться опытом — подавайте заявку на доклад
Билеты можно приобрести здесь. Вы можете успеть купить их до повышения цены!
Следите за нашими новостями — Telegram, Twitter, VK и FB и присоединяйтесь к обсуждениям.
namikiri
Вот очень, очень напрягает, когда, например, удаляешь элемент из списка, он пропадает, но на самом деле никуда он не пропал и запрос всё ещё идёт. Ещё хуже, когда бэкенд сообщил об ошибке, а фронт как ни в чём не бывало показывает что элемента нет, или, например, выводит «Ошибка» (да, тупо одно слово, за это отдельный минус), а элемент назад уже не возвращается.
Нет, ребята, я лучше посмотрю на вращающийся спиннер и подожду пока операция реально завершится — такое поведение даёт более прочное ощущение контроля над ситуацией, а не «оно там что-то как-то шурупит». Именно за это я не люблю максимально асинхронные интерфейсы — они делают что-то, чего я не понимаю и не могу контролировать, я не ощущаю работы системы, мне остаётся лишь — сюрприз! — ждать результата и гадать, а есть ли он вообще.
obenjiro
Давайте попробуем рассмотреть контрпример. Представьте что спинер крутиться бесконечно и лишь через 10 минут открыв консоль вы видите, что ошибку не обработали. Я не буду рассказывать сколько раз я этот пример видел в реальной жизни.
Я могу быть не прав, но мне кажется вас бесит не skeleton или optimistic updates, а просто криворукие сайты написанные на коленке :)
gecube
так пускай крутится сколько-то времени, а потом вываливается сообщение об ошибке (в интерфейсе). В чем проблема так сделать ?
obenjiro
Ну вот и я о том-же :) Бесит обычно не конкретный подход а его реализация. Ну и сама необходимость сидеть и чего-то ждать, на что-то смотреть.
namikiri
Я об этом и говорил — не надо пытаться меня обмануть. Недосмотр и попытка сделать вид что всё хорошо — немного разные случаи.
RouR
Пожалуйста не используйте трюк с mousedown.
Если пользователь промахнулся по кнопке, нажал и не отпустил, то ещё есть шанс всё исправить — увести клик за пределы кнопки, события onclick не будет. Трюк с mousedown ломает этот UX.
obenjiro
Хорошее замечание! Но все зависит от того какое действие вы делаете на mousedown. Если переход на страницу то да — будет полных треш.
Но я говорю немного о другом. На mousedown вы можете начать скачивать ресурсы следующей страницы, предзагружать контент, в общем выполнять любую подготовительную работу и только после события click — «визуально» выполнять действие (выполнять переход, обрисовывать элементы)
PS: но с общим посылом не спорю, добавлю замечание в статью
Bruce_Robertson
glebmachine код скринами сделан специально? :-)
glebmachine Автор
Это расшифровка доклада, скрины с презентации(
gecube
запросить презентацию в текстовом формате (PDF, PPTX)?
obenjiro
Взял право на редактирование. Исправил! Спасибо за терпение!
spc
По ощущениям, ничего меня не бесит больше, чем эти самые скелетоны-плейсхолдеры. Но я не знаю, может есть аудитория, которая в восторге.
obenjiro
А можно конкретные примеры? Я не спорю, просто интересно :)
spc
Больше всего, конечно, раздражают Почта России, Пятерочка и Тинькофф, которые могут сверкать этими самыми скелетонами чуть не полминуты:
Catslinger
Вообще, такая проблема есть везде. Я считаю, что KDE имеет славу тормозного пугала в первую очередь из-за слишком медленных анимаций — разворачивания меню, перехода между окнами, кнопок. Стоит их ускорить в настройках — и появляется ощущение, что всё летает.
obenjiro
Извучал анимацию (как правилно рисовать мультики). Так вот есть 1 интересный принцип. Чем плавнее и медленней анимация движения, тем больше кадров должно быть чтобы анимация выглядела «естественно». Соответственно, чем медленней анимация UI тем быстрее его отрисовка должна быть (больше FPS), к сожалению KDE этим не славилась (в свое время), что приводило к тому что помимо обычных проблем с производительнотью — долгая, плавная анимация делала этот UI неестественным.
Для себя сделал правило не делать долгих transiton особенно в высоконагруженных приложениях
koch777
Про аэропорт интересная история.
;-)
Учитывая, что Штатах есть два таких места:
Аэропорт Hustons в Индиане с одной грунтовой полосой аж в 700 метров.
Аэропорт в местечке Huston в Айдахо, который вертолетная площадка.
Боюсь ни в одном из них нет транспортеров или даже места для выдачи багажа.
Или речь про другую страну?
gecube
Maybe Houston, TX?
koch777
:-) Это шутка была.
Конечно Houston, но меня на секунду сбило при чтении
obenjiro
На сколько я понял речь о George Bush Intercontinental/Houston Airport (IAH)
obenjiro
Исправил и добавил ссылку на оригинальную статью www.nytimes.com/2012/08/19/opinion/sunday/why-waiting-in-line-is-torture.html
warhamster
Интересно, было бы ли исследования на аудитории из разработчиков — прекрасно знающей, что любые анимации и трюки типа скелетонов предназначены лишь для скрытия тормозов. Мне кажется, результаты бы заметно отличались.
obenjiro
К сожалению, даже если ты знаешь об этом, это все равно работает :)
Как это проверить? Посмотрите на The Coyote Illusion из секции «Обманывайте», главный элемент этой иллюзии скорости Motion Blur. Это все связанно с таким интересным эффектом как Chronostasis (это я не про мангу). Есть очень много интересных научных исследований о том как человек (довольно часто) ошибается с оценкой времени.
Время для человека — величина эмоциональная.
Ну а про популярность данных методик и говорить особо не стоит. Все онлайн игры используют Latency Compensation (Optimistic Updates). Twitter один из ярких представителей вебсайтов который использует эту технику. Про скелетоны вообще молчу. И поверьте почти за каждым из таких внедрений стоят исследования, а не слепое — давайте воткнем. Поэтому и писал что прежде чем это все внедрять стоит проверить полезность на вашем конкретном сайте. Слава богу с сервисами вроде Яндекс.Толока это не так дорого и сложно.