Оптимізація вебзастосунків: лайфхаки та інструменти

Привіт! Я — Олег, Team Lead в ІТ-компанії Quarks, що спеціалізується на створенні продуктів і технологій у сфері Social Discovery та онлайн-знайомств. Я працюю в ній уже три роки. Зараз керую командою, яка займається розробкою SPA, куди входять фронтенд-девелопери та QA.

У цій статті хочу розповісти про оптимізацію вебзастосунків, поділитися нашим досвідом та рішеннями, які допомогли значно покращити продукт. Стаття буде корисною розробникам рівнів джуніор та мідл.

Чому важливо оптимізувати вебзастосунок? Найдорожче, що є у наших користувачів — це їхній час. За нього доводиться боротися з безліччю інших застосунків. Щоби привернути їхню увагу та завоювати прихильність, у нас є всього декілька секунд. Рідше — декілька хвилин, якщо у користувача поганий інтернет.

Чим швидшим та інтерактивнішим буде застосунок, тим ймовірніше його оберуть серед багатьох інших, користуватимуться та витрачатимуть на нього кошти. Оптимізація вебзастосунку покращує UX, дає можливість пришвидшити роботу, без затримок користуватися інтерфейсом та має прямий вплив на фінансові показники компанії.

Основні метрики оптимізації

Є ряд метрик, за якими можна виміряти ефективність вебзастосунків. Для кожного продукту це індивідуально, і необовʼязково всі показники мають бути ідеальними. Скоріше їх варто розглядати, як велику недосяжну ціль, рухатися в її напрямку і покращувати свій продукт та інтеракцію з ним. Розглянемо детальніше чотири метрики.

1. First Paint (FP) and First Contentful Paint (FCP)

First Paint (FP) — час, коли на екрані вже хоч щось «відмалювалося», і користувач бачить первинну комунікацію від продукту. Для нього це знак, що нічого не глючить і «щось відбувається». Усі користувачі — чутливі до очікування, їм треба одразу бачити зміни. Тому ця метрика — один з перших пунктів для покращення.

First Contentful Paint показує час, коли на екрані вже з’явився весь контент, який має відобразитися, і користувач може комунікувати з ним. По суті різниця в тому, що First Paint — це перший етап відмалювання екрану, а First Contentful Paint — це другий.

2. Time to Interactive

На мою думку, це найважливіший показник. Він відображає час, за який користувач починає комунікувати з вашим продуктом. І його потрібно намагатися максимально скорочувати. Інтерактив заохочує користувача до взаємодії з вашим застосунком, і ви зможете довше втримати його зацікавленість.

3. Peak Response Time

Ця метрика актуальна для великого продукту, показує кількість людей, які можуть одночасно користуватися ним. Наприклад, інтернет-магазин під час новорічних розпродажів.

Продукт має бути готовим до того, що в певний період кількість відвідувань може збільшитися в 10-20 разів, і все має працювати так само швидко, як у звичайний час.

4. Page Speed and Load Time

Це загальний показник, як швидко сторінка реагує на дії користувача — завантажуються фотографії, контент, нові користувачі, товари тощо.

Для аналізу цих метрик можна використовувати Google Analytics, Hotjar та інші аналітичні інструменти. Найголовніше — заходити на панель девелопера, а саме в розділи Network та Performance. Там можна побачити багато корисної інформації: як довго завантажується кожен елемент вашого сайту, скільки проходить часу від моменту, як перші байти приходять до клієнта до повного відображення сторінки, як відпрацювали ті чи інші запити до сервера або як завантажуються картинки.

Є багато методів, якими можна покращити швидкість завантаження чи інтеракції. Умовно їх можна розділити на три категорії: покращення роботи з фотографіями, оптимізація роботи з кодом та покращення з боку сервера.

Оптимізація роботи з фотографіями

Візуальні ефекти займають найбільше часу з точки зору комунікації з користувачем та їхнього завантаження. Тому оптимізації цього виду контенту варто приділити увагу в першу чергу.

Формат

Перше, що можна зробити — подивитися на формати (JPEG, PNG, GIF тощо) та уніфікувати їх. Найпопулярніше рішення — використовувати JPEG, адже він потребує менше місця для зберігання, передає менше кольорів, має просту структуру та підтримується у всіх браузерах.

Також варто звернути увагу на WebP — відносно новий формат для оптимізації зображень. Він в середньому на 26% менший за PNG та на 25-34% менший за JPEG з тим самим індексом SSIM. Формат AVIF також забезпечує хорошу компресію, але наразі має обмеження підтримки у браузерах.

Віжуал:

Компресія

Модель кольорів

Підтримка

Максимальний розмір

JPEG

Найпопулярніший формат для зображень

Lossy

8 bit

Chrome, Edge, Firefox, Internet Explorer, Opera, Safari

65,535×65,535 pixels

PNG

Растровий формат збереження графічної інформації, що використовує стиснення без втрат

Lossless

8/16 bit

Chrome, Edge, Firefox, IE, Opera, Safari

2,147,483,647×2,147,483,647 pixels

GIF

Підходить для простих зображень і анімації

Lossless

8 bit

Chrome, Edge, Firefox, Internet Explorer, Opera, Safari

65,536×65,536 pixels

AVIF

Підходить для статичних та анімованих зображень. Забезпечує краще стиснення, ніж PNG або JPEG, але має обмеження підтримки у браузерах

Lossless / lossy

8/10/12 bit

Chrome 85, Opera 71, Firefox 93, Safari 16.1.

2,147,483,647×2,147,483,647 pixels

WEBP

Підходить для статичних та анімованих зображень. Стискає з підтримкою більшої глибини кольору, анімованих рамок, прозорості тощо

Lossless / lossy

8 bit

Chrome, Edge, Firefox, Opera, Safari

16,383×16,383 pixels

Джерело

На нашому продукті користувачі завантажують величезну кількість фотографій, і перехід на WebP зміг кратно покращити та пришвидшити застосунок. Раніше у цього формату виникала проблема з підтримкою в деяких браузерах.

У такому випадку ми використовували JPEG. Але зараз всі популярні браузери, включно з проблемним Safari, вже підтримують WebP.

Розмір

У вебпродуктах ми часто використовуємо статичні креативи (фони, банери тощо). Часом дизайнери не дуже замислюються над оптимізацією та можуть віддати картинку в 4К. За цим треба слідкувати та намагатися використовувати якомога менші файли.

У цьому допоможуть інструменти на кшталт TinyJPG та TinyPNG, які можуть оптимізувати картинку на 30-60-80 та навіть 90%.

Crop

Слідкуйте за тим, який розмір картинки використовуєте в тому чи іншому місці. Щоби відобразити аватарку користувача та просто показати, що це він, немає потреби у великих повнорозмірних фотографіях, втиснутих у маленький простір.

За допомогою інструментів на бекенді чи самостійно вирізайте такий розмір картинки, який потрібен для завантаження цієї сторінки.

Використання віжуалів відповідно до потреб

Цей лайфхак доволі банальний, але неоптимізовані картинки використовують часто. Якщо адаптивний лендинг на великому екрані потребує відповідної картинки, то на мобільному телефоні можна використовувати значно менші розміри.

Приклади завантаження зображень у різних розширеннях:

1.

<img

srcset="elva-fairy-480w.jpg 480w, elva-fairy-800w.jpg 800w"

sizes="(max-width: 600px) 480px,

800px"

src="elva-fairy-800w.jpg"

alt="Elva dressed as a fairy" />

2.

<picture>

<source media="(max-width: 799px)" srcset="elva-480w-close-portrait.jpg" />

<source media="(min-width: 800px)" srcset="elva-800w.jpg" />

<img src="elva-800w.jpg" alt="Chris standing up holding his daughter Elva" />

</picture>

Більше про оптимізацію картинок можна прочитати тут.

Оптимізація роботи з кодом

Компресія

Якщо розмір застосунку перевищує 1 Мб, це вже доволі великий продукт зі значним об’ємом коду. Він може завантажуватися довго та проблематично. Найкращий спосіб виправити це — використовувати компресію.

Є низка алгоритмів стиснення даних, які допомагають пришвидшити завантаження вебсторінки. Ми користуємося сервісом Cloudflare, який застосовує компресію за алгоритмами Brotli або Gzip. Це дозволяє зменшувати CSS та JS файли до оптимального розміру на стороні сервера. З їхньою допомогою компресія може досягати десятків разів.

Показники до та після використання Gzip:

Бандлінг файлів

Це поєднання файлів JS та CSS в один/ декілька файлів для кращого завантаження.

Будь-який продукт можна розділити та віддавати людині частинами. Наприклад, у кожного продукту є умовні налаштування, до яких користувач рідко звертається. Їх можна відокремити від основної частини продукту та завантажувати тільки за необхідності, коли користувачу безпосередньо потрібна ця частина.

Якщо поділити продукт на 5-6 частин та компресувати кожну з них з допомогою gzip, це значно пришвидшить застосунок.

Важливо: найбільш дієво цей метод працює у звʼязці з наступним.

Мініфікація

Цей метод передбачає видалення коментарів, непотрібних символів, довгих назв змінних, зайвих пробілів, перенесення рядків тощо. У результаті ви отримаєте програмний код, записаний в один рядок. Такий спосіб не дозволяє суттєво заплутати його, але допомагає зменшити об’єм та зробити компактнішим.

Важливо зменшувати лише код, який ви розповсюджуєте, а не вашу вихідну версію, оскільки мініфікований код важче читати та виправляти баги. У ньому довгі назви та коментарі можуть бути позначені лише однією літерою. І якщо на продакшені виникне критична помилка, і ви побачите незрозуміле повідомлення, source map допоможе правильно розшифрувати його та зрозуміти, що саме зламалося. Це певний ключ-опис, який дозволяє коректно відобразити, що ми мініфікували.

Використання Content Delivery Network (CDN)

Ще один спосіб — використовувати CDN-сервіси, які зберігають статичні файли CSS, JS, картинки, іконки. Якщо всі файли знаходяться на сервері на заході України, користувач з Бразилії буде дуже довго завантажувати продукт. Розміщення статичних файлів на CDN-серверах може значно пришвидшити час доставки.

Методи попередньої вибірки, підключення та пререндерингу

Також є ряд браузерних механік, які допомагають пришвидшити підвантаження даних та сайтів через попереднє підключення до них.

DNS prefetching. Ви можете сповістити браузер, що певні доменні імена будуть використовуватись у майбутньому. І він зможе спробувати заздалегідь визначити IP-адресу. Ця невелика оптимізація може мати значний ефект у поєднанні з іншими прийомами.

<link rel="dns-prefetch" href="//example.com">

Prefetching. Якщо ви впевнені, що конкретний ресурс буде потрібний у майбутньому, ми можемо попросити браузер завантажити його в фоні та зберегти в кеші.

<link rel="prefetch" href="logo.png">

Prerendering. Коли ви точно знаєте, що ваш користувач перейде на певну сторінку, ви можете сповістити браузер про необхідність попередньо відмалювати її та завантажити всі додаткові матеріали, вказані в URL, як тут:

<link rel="prerender" href="https://www.example.com/next-page">

Зменшення кількості плагінів та сторонніх бібліотек

Один з найпростіших способів оптимізувати продукт — перевірити, чи немає нічого зайвого у коді, сторонніх бібліотек або плагінів, що не використовуються. Також ви можете поділити бібліотеки на маленькі бандли та використовувати тільки ту інформацію, яка потрібна у продукті. Проаналізувати та оптимізувати це можна з допомогою інструмента Webpack Bundle Analyzer. Він показує, що входить в бандли, займає найбільшу частину та може бути зайвим.

Оптимізація взаємодії з API-сервером

Слідкувати за необхідністю та критичністю даних, що використовуються на екрані

Наприклад, у нашому застосунку можна подивитися список людей, які заходили на твою сторінку. У ньому відображається всього три параметри: імʼя, аватарка та статус онлайн/ офлайн.

При цьому якщо зробити загальний запит, бекенд може прислати всю інформацію про цих користувачів, яка в нього є: знак зодіаку, фотографії, активні підписки, інтереси тощо. Всі ці дані є зайвими, оскільки не відображаються на екрані. І таких користувачів може бути 20, по кожному з яких бекенд надішле 30 параметрів замість 3.

Чим більше даних запитується, тим більше часу це може займати. Виходить, що ми використовуємо ресурси для отримання зайвої інформації, в якій немає потреби.

Рішення: робити індивідуальні запити під конкретні задачі. Ми можемо формувати ендпоінти для рішення певних проблем на цій ділянці інтерфейсу з обмеженою кількістю інформації, яка тут потрібна.

Зменшити кількість HTTP-запитів

Також варто звертати увагу на кількість HTTP-запитів, які клієнт відправляє на сервер.

Уникаючи зайвої інформації в попередньому прикладі, можна прийти до хибного рішення — робити запити на ID користувачів, а потім окремі запити на параметри. Це також поганий шлях вирішення проблеми. Через те, що їх треба буде виконувати по черзі, ми збільшимо час очікування у 2 рази.

Чим більший RTT, тим довше доведеться чекати. Це нераціонально використовує час користувача і ресурси ваших серверів.

При широкій географії користувачів використовувати сервери на різних континентах

Подумайте про необхідність розташування серверів з базами даних на різних континентах у безпосередній близькості до ваших користувачів. Як би ви круто не зменшили код JS файлу та не пройшли усі вищеперераховані кроки, якщо користувачі з одного континенту слатимуть запити на сервер, що знаходиться на іншому, це дуже уповільнить роботу застосунку.

Наприклад, показники RTT між серверами в різних точках світу:

  • в межах одного міста — близько 1 мс;
  • Amsterdam, Netherlands — Luxembourg — 7-10 мс;
  • Amsterdam, Netherlands — San Francisco, US — 140 мс;
  • London, UK — Hong Kong — 186 мс;
  • Singapore — Washington D.C., US — 234 мс;
  • San Francisco, US — Hong Kong — 265 мс.

Ці показники — чиста затримка між серверами. Якщо додати до неї час на очікування відповіді сервера, бази даних та інші потенційні затримки, ваш застосунок працюватиме повільно. Якщо ви не можете дістати дані про користувача протягом однієї секунди — це однозначно фейл.

Звичайно, ці цифри доволі відносні, але якщо ми прагнемо, щоби юзери користувалися сервісом безпроблемно, це варто виправити.

Висновки

Враховуючи кількість девайсів, операційних систем та умов, кожен продукт є унікальним за показниками та необхідними покращеннями. Відповідно план дій з оптимізації для кожної команди буде різним. Озброївшись трекінгом користувацької активності та КРІ продукту, сфокусуйтеся в першу чергу на оптимізації вузьких місць. Це принесе найбільшу користь найменшими зусиллями.

Оптимізація — непростий процес, у якого немає кінця. Аналізувати продукт та шукати способи, як його покращити потрібно безперервно. Відсутність фінальної точки може демотивувати. Але усі ці дії можуть суттєво покращити продуктові та фінансові показники вашого продукту.

👍ПодобаєтьсяСподобалось12
До обраногоВ обраному9
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Я б ще додав, що можна мініфікувати HTML
— Всі забувають що в Apache і Nginx є режими Zip or Gzip compression
— А також кешування скриптових мов програмування на рівні скомпільованого коду (для PHP це OpCache), або можна JIT двіжок використать замість Zend.
Але це все як і пререндеринг — навантаження на сервер.
— В деяких випадках може допомогти лінива загрузка, використання веб-сокетів або SSE.

Ну і оптимізацію коду, запитів в базу даних, винесення частини коду в черги чи в кеш ніхто не відміняв.

Здорово! От себя напоминаю, что http/2 снижает преимущество бандлинга. А gzip + кеширование статики на Cloudflare возможно снижает преимущество от минификации. Кроме того, если не используется Typescript возможно стоит не забывать про нативные импорты модулей.

Підписатись на коментарі