Чому мікрооптимізації не допомагають покращити справжню продуктивність JavaScript
Пояснює, чому погоня за вимірюваними показниками, такими як розмір пакету та кількість повторних відрендерингів, часто не допомагає виявити справжні причини повільної роботи додатків на JavaScript.
На папері цей pull request виглядав надійно.
Розмір бандлу зменшився на 18 відсотків. Кілька невикористовуваних залежностей було видалено. Кілька компонентів було обгорнуто механізмом мемоїзації. Кілька операцій з масивами було замінено на, нібито, ефективніші цикли. Оцінка Lighthouse піднялась. Кожен показник у описі PR вказував у правильному напрямку.
Команда схвалила його без вагань.
Через два тижні користувачі все ще казали, що додаток працює повільно.
Не таке повільне, коли „бенчмарк показує кілька додаткових мілісекунд“.
Це не проблема з цифрами на панелі керування.
Це та повільність, яка справді впливає на людей.
Вони натискали кнопку та не були впевнені, чи вона була зафіксована.
Вони відкривали екран та сиділи, чекаючи, поки з’явиться щось корисне.
Вони змінювали фільтр та бачили, як інтерфейс на мить замерзає, перш ніж повернутися до роботи.
Команда доклала справжніх зусиль до покращення продуктивності.
Проте вони спрямували їх на неправильні цілі.
Ця тенденція постійно спостерігається у сучасних проектах на JavaScript.
Незважаючи на кращі інструменти аналізу продуктивності, швидші часи виконання, розумніші засоби об’єднання коду, більш потужні фреймворки та постійно розвиваючіся браузери, розробники продовжують дотримуватися однієї й тієї самої звички:
Оптимізувати те, що найлегше виміряти, а не те, що насправді впливає на користувачів.
JavaScript пропонує безліч елементів, які можна оптимізувати.
Компонент перерисовується чотири тисячі разів — отже, ви це виправляєте.
Розмір пакету становить 300 КБ — отже, ви його скорочуєте.
Функція виконується за 12 мілісекунд — отже, ви її переписуєте.
Залежність займає 40 КБ — отже, ви її видаляєте.
Мікротест показує, що підхід А перевершує підхід B на 7 відсотків.
Отже, ви обираєте A.
Кожен з цих варіантів може бути легітимною роботою.
Але жоден з них автоматично не призводить до кращого досвіду користування для того, хто використовує ваш додаток.
Іноді найшвидший код, який ви пишете, — це рішення проблеми, яка нікого навіть не турбувала.
Тим часом повільний запит до бази даних, зайвий мережевий виклик, незграбна послідовність завантаження, перевантажений пакет API чи погано спроєктована взаємодія тихо коштують користувачам реального часу.
Саме ця невідповідність є справжньою проблемою, яку варто дослідити.
Продуктивність — це не те саме, що швидкість
Одним із найкорисніших уроків роботи з продакшн-системами є те, що продуктивність не можна звести до одного показника.
Додаток може бути максимально ефективним з точки зору обчислень навіть на рівні мікросекунди, але все одно залишатися дуже незручним у використанні.
Уявіть сторінку, яка виконує таку послідовність дій:
- Завантажте оболонку додатка.
- Завантажте кілька фрагментів JavaScript.
- Запустіть фреймворк.
- Отримайте дані конфігурації.
- Отримайте інформацію про поточного користувача.
- Отримайте дані про дозволи.
- Отримайте вміст панелі керування.
- Відобразіть панель керування.
- Отримайте сповіщення.
- Відобразіть сповіщення.
Кожен окремий крок може бути дуже швидким сам по собі.
Справжня проблема — це вся послідовність дій.
Користувачам не важливо, чи було кожен елемент окремо налаштований оптимально.
Їх хвилює те, що вони дивляться на порожній екран, поки щось не з’явиться.
Саме тому будь-яке справжнє дослідження продуктивності має починатися з одного запитання:
На що насправді чекає людина з іншого боку?
А не:
Як мені скоротити час виконання цієї функції?
Це принципово різні напрямки досліджень.
Розробник може витратити три години на те, щоб скоротити час виконання функції з 8 мс до 3 мс.
Тим часом сторінка залишається нерухомою протягом 700 мс, чекаючи на запит, який ніколи не мав виникати.
Це не справжня оптимізація.
Це наче прибирання меблів, поки в стіні за ними проривається труба.
Одержимість 5 мілісекундами
Розробники JavaScript мають особливу схильність до мікрооптимізацій.
Частина цього інтересу справді є корисною.
Люди сперечаються про використання циклів for та методу map().
Вони обговорюють стратегії виділення пам’яті.
Вони досліджують приховані класи, поведінку збору сміття, закриття функцій, витрати на деструктуризацію, накладні витрати на виклик функцій та оптимізації JIT.
За всім цим стоїть справжні, корисні знання.
Проблема не у розумінні цих механізмів.
Проблема у тому, що до них вдаються без жодних доказів того, що вони тут мають значення.
Припустимо, функція виконується 100 разів під час однієї взаємодії користувача.
Наразі кожне викликання займає 2 мс.
Ви витрачаєте півдня, щоб скоротити цей час до 1 мс.
Загальна економія: 100 мілісекунд.
Це може мати певну цінність.
Але припустимо, що під час тієї самої взаємодії відбувається також зайвий виклик API, який вирішується протягом 600 мс.
Видалення цього виклику займе п’ять хвилин та дозволить заощадити у затримці в шість разів більше, ніж уся ваша післяобідня робота з оптимізації.
Якщо говорити просто, це здається очевидним.
Проте під час обговорень коду увага зосереджується на першому типі проблем, тому що вона безпосередньо видно у різницях коду.
Натомість зайвий мережевий виклик може бути прихований на трьох рівнях абстракції.
Це призводить до передбачуваної та небезпечної схильності:
Команди оптимізують код, який є видимим для них, а не систему, яку насправді використовують їхні користувачі.
Браузер — це не ваша функція
Ще однією поширеною помилкою є припущення, що час виконання JavaScript розкриває всю картину продуктивності.
Це зовсім не так.
Додаток, створений на основі браузера, — це ціла система, а не просто один виклик функції.
Ця система включає:
- Розв’язування DNS
- Встановлення з’єднання
- Обмін даними TLS
- Обробка на стороні сервера
- Запити до бази даних
- Серіалізація відповідей API
- Час передачі даних по мережі
- Аналіз HTML
- Аналіз JavaScript
- Виконання JavaScript
- Відображення контенту
- Розрахунок макету
- Нанесення елементів на екран
- Композиція зображень
Кожен із цих етапів може вплинути на те, наскільки швидко щось відчувається користувачем.
Припустимо, вам вдається скоротити час відображення компонента React з 15 мс до 8 мс.
Це справді гарна робота.
Але якщо бекенд потребує 900 мс для отримання даних, необхідних цьому компоненту, ваше покращення майже не помітне.
Або, можливо, сервер відповідає швидко, але надсилає 2 МБ JSON для відображення, якому потрібно лише 20 КБ.
Тепер ви витрачаєте цикли CPU та пропускну здатність на передачу даних, які взагалі не повинні існувати у такій формі.
Або, можливо, сторінка завантажує величезну бібліотеку з клієнтської сторони, перш ніж зможе відобразити щось значуще.
Жодна з цих проблем не є проблемою компонента.
Це проблеми архітектури.
Ось чому серйозна робота з оптимізації продуктивності часто більше схожа на розслідування, ніж на просте „зробити JavaScript швидшим“.
Ви визначаєте причину затримки та йдете до її джерела, куди б це не привело.
Найдорожча операція — це часто та, яку варто пропустити
При роботі над покращенням продуктивності існує корисний порядок пріоритетів.
Прискорення операції — це хороший результат.
Пропуск цієї операції повністю зазвичай є кращим варіантом.
Уявіть собі цей уривок:
const results = expensiveTransform(items);
Аналіз продуктивності показує, що ця трансформація займає 40 мс.
Ваш інстинкт може підказувати оптимізувати її.
Можливо, ви введете кеш.
Можливо, заміните її на більш ефективний алгоритм.
Можливо, перенесете цю роботу зовсім в інше місце.
Але перш ніж робити щось з цього, запитайте себе:
Чому взагалі відбувається ця трансформація?
Можливо, результат змінюється лише тоді, коли налаштовується фільтр.
Можливо, ви все одно запускаєте його під час кожного відтворення.
Можливо, бекенд міг би надати вам вже оброблену версію.
Можливо, інтерфейс насправді не потребує всіх 10 000 рядків.
Можливо, ви завантажуєте дані, які користувач ніколи не відкриє.
Справжнє рішення може взагалі не знаходитися всередині expensiveTransform().
Можливо, достатньо просто видалити цей виклик.
Цей підхід добре застосовується не лише до цього прикладу.
Пропускайте запити, які вам не потрібно надсилати.
Пропускайте відтворення UI, яке залишається прихованим.
Пропускайте обчислення значень, які ніхто не буде використовувати.
Пропускайте шляхи коду, які користувачі ніколи не активують.
Пропускайте обробку даних, які можна було б відфільтрувати на ранніх етапах.
Пропускайте повторну роботу, результат якої насправді не змінився.
Найшвидшою операцією залишається та, яка взагалі не виконується.
Розмір пакету — це не все
Розміру пакету справді варто приділити увагу. Це безумовно правда.
Але оскільки цей показник так широко використовується, команди іноді починають сприймати його як замінник самої продуктивності.
Команда скорочує розмір свого JavaScript-пакету на 50 КБ та вважає це успіхом.
У той же час додаток все ще надсилає шість запитів поспіль, перш ніж користувач зможе щось зробити.
Звісно, пакет став меншим.
Але це не означає автоматично, що якість використання покращилась.
Це зовсім не означає, що розмір пакету є неважливим.
Це означає, що потрібно з’ясувати коли саме цей JavaScript-код фактично використовується.
100-КБ скрипт, який блокує початкову інтерактивність, може мати набагато більше значення, ніж 300-КБ скрипт, який завантажується пізніше для функції, якою користувач може скористатися лише раз на місяць.
Час виконання має значення.
Момент виконання коду також має значення.
Важливо, на якому пристрої він працює.
Важливо також мережа, через яку він передає дані.
Важливо наявність кешування.
І, не менш важливо, важливо те, що саме намагається зробити користувач.
Якщо певна функція використовується рідко, завантаження всього необхідного під час запуску може бути невдалим рішенням.
Розділення коду допомагає у цьому.
Так само, як і лежерне завантаження.
Але обидва підходи можуть перетворитися на марні дії, якщо застосовувати їх без реального розуміння того, як насправді завантажується сторінка.
Питання, яке варто поставити, не є таким:
Як нам ще більше скоротити цей пакет?
Воно є таким:
Що саме потрібно цьому конкретному користувачеві у цю мить, і наскільки швидко ми можемо зробити цю конкретну річ придатною до використання?
Саме такий підхід допоможе досягти значно кращих результатів.
Компонент, на який ви дивитеся, може не бути причиною проблеми
Кожен, хто працював з React, розпізнає цей цикл.
Компонент перерендрується більше, ніж слід.
Хтось вдається до useMemo.
Один зайвий рендер зникає.
Усі задоволені.
Потім така сама ситуація трапляється з наступним компонентом.
Незабаром кодова база наповнюється викликами мемоізації:
const filtered = useMemo(
() => expensiveFilter(items, query),
[items, query]
);
const handleClick = useCallback(() => {
doSomething(id);
}, [id]);
const value = useMemo(
() => ({ user, permissions }),
[user, permissions]
);
Іноді це справді правильний крок.
Іноді ж це лише ускладнює розуміння коду, не вирішуючи при цьому нічого суттєвого.
Оптимізація — це не безкоштовно.
Мемоізація зокрема має реальні витрати.
Вона збільшує навантаження на пам’ять, потребує підтримки масивів залежностей, додає додаткове когнітивне навантаження та створює нові місця для приховування тонких помилок.
Вимірюйте перед тим, як вдаватися до неї.
Якщо певні обчислення займають 0,2 мс та виконуються рідко, їх оптимізація не принесе жодної користі.
Якщо вони займають 50 мс та виконуються при кожному натисканні клавіші, це зовсім інша ситуація.
Мета не в тому, щоб перевіряти кожне повторне відображення.
Мета — зробити важливі взаємодії достатньо швидкими.
Ці дві мети не є ідентичними.
Зосередьтесь на взаємодіях, а не на окремих компонентах
Саме тут багато команд могли б отримати користь від зміни підходу.
Користувачі не сприймають компоненти як окремі одиниці.
Вони відчувають те, що роблять.
Вони вводять запит до пошуку.
Вони заповнюють поля.
Вони переміщаються між сторінками.
Вони надсилають форму.
Вони відкривають спадний список.
Вони перемикаються між вкладками.
Вони завантажують файл.
Вони прокручують ленту новин.
Вони сидять та чекають, поки щось з’явиться.
Замість того, щоб запитувати:
Чи добре оптимізований цей компонент?
Спробуйте запитати:
Чи здається введення тексту у це поле пошуку миттєвим?
Замість того, щоб запитувати:
Чи ефективно відображається цей список?
Краще запитати:
Чи може хтось плавно прокручувати цей список, без затримок у інтерфейсі?
Замість того, щоб запитувати:
Чи скоротили ми кількість відображень React?
Краще запитати:
Чи дає натискання на цю кнопку користувачеві миттєву та зрозумілу відповідь?
Ця друга група запитань набагато точніше відображає те, що насправді має значення для продукту.
Розумна оптимізація, яка залишає важливу взаємодію такою ж повільною, як і раніше, не є обов’язково цінною інженерною рішенням, незалежно від того, наскільки елегантною вона виглядає у файлі зі змінами.
Вкладка „Мережа“ зазвичай краща за цикл, який ви переписуєте
Перш ніж торкнутися хоча б одного циклу, відкрийте панель мережі вашого браузера.
Це не якась випадкова порада.
Часто ви знайдете там більше можливостей для покращень, ніж у сотнях рядків вручну налаштованого JavaScript.
Звертайте увагу на таке:
- однаковий запит, який надсилається більше одного разу
- запити, які виконуються один за одним, хоча могли б працювати паралельно
- запити, які починаються ще до того, як їхні дані дійсно знадобляться
- відповіді, які є надто об’ємними порівняно з тим, що відображається
- кешування, яке мало б існувати, але не існує
- запити, які виконуються частіше, ніж це необхідно
Один зайвий запит може мати більший вплив, ніж десятки незначних змін у JavaScript.
Візьмемо пошук як приклад.
Ось наївний підхід:
User types "j"
→ request
User types "ja"
→ requestUser types "jav"
→ requestUser types "java"
→ request
Команда може потім докласти значних зусиль, щоб прискорити відображення результатів.
Але справжньою проблемою може бути те, що додаток надсилає чотири окремі запити, тоді як достатньо одного.
Використання механізмів затримки запитів, скасування запитів, кешування та краще спроєктованих запитів зазвичай дає набагато кращі результати.
Саме такі покращення відбуваються на рівні системи, а не всередині окремої функції.
Не оптимізуйте неправильний пристрій
Виконання тесту продуктивності на власному розробницькому комп’ютері майже нічого не говорить про те, як дійсно працює додаток на старому телефоні з обмеженою продуктивністю процесора та нестабільним з’єднанням.
Це має величезне значення для JavaScript.
Сучасне обладнання може обробляти значну кількість коду, і розробник навіть не помітить уповільнення.
Потужний ноутбук може приховувати проблеми.
Флагманський телефон може приховувати проблеми.
Швидка офісна мережа може приховувати проблеми.
Робота локально також може приховувати проблеми.
А потім справжня людина відкриває додаток на пристрої низького класу через нестабільне з’єднання.
Раптово цей ретельно налаштований додаток починає працювати повільно та нереактивно.
Саме тому так важливо тестувати за реалістичних умов.
Вам не потрібно робити це постійно.
Але потрібно робити це достатньо часто, щоб команда мала реальне уявлення про те, як працює додаток поза зручним середовищем розробки.
Правильне запитання не є таким:
Чи здається це швидким на моїй конфігурації?
Воно є таким:
Чи достатньо це швидко для справжніх користувачів?
Архітектура зазвичай краща за мікрооптимізацію
Це, мабуть, найважливіший урок з усіх.
Саме архітектура визначає верхню межу продуктивності.
Якщо ваш додаток мусить виконати п’ять запитів API по черзі, перш ніж зможе показати свою основну сторінку, жодні хитромудрі маніпуляції з масивами не виправлять цю ситуацію.
Якщо кожен маршрут завантажує весь пакет додатку, видалення кількох допоміжних функцій не вплине на справжню проблему.
Якщо клієнт завантажує величезний набір даних, а потім фільтрує його у браузері, оптимізація логіки фільтрації, ймовірно, менш важлива, ніж виправлення самого контракту API.
Якщо якась дія користувача видаляє значну частину кешованого стану, обгортання компонентів у механізм мемоїзації не виправить пошкоджену стратегію анулювання даних.
Якщо ви одночасно відображаєте тисячі елементів DOM, зміна способу використання map() не допоможе вам заощадити ресурси.
Покращення, які справді приносять ефект, зазвичай полягають у зміні де виконується робота, коли вона виконується або чи взагалі потрібна вона.
Це архітектурні рішення, а не корективи на рівні коду.
Що я насправді перевіряю під час дослідження продуктивності
Коли щось здається повільним, слід стримувати бажання одразу ж занурюватися в код.
Почніть з відтворення проблеми.
Потім запитайте, на що саме користувач там сидить і чекає.
З цього моменту розслідування зазвичай ведеться за певною послідовністю.
1. Завантаження
Що має статися, перш ніж користувач зможе побачити та використовувати важливі частини сторінки?
Відстежте критичний шлях.
Які ресурси справді необхідні?
Які запити блокують прогрес?
Що завантажується, коли цього не потрібно?
2. Мережа
Відкрийте панель Мережа.
Шукайте закономірності у форматі «водоспаду».
Ланцюги послідовних запитів вимагають уважної перевірки.
Так само як і дубльовані виклики та дані, об’єм яких перевищує необхідний рівень.
3. Отримання зображення
Далі перевірте, що саме робить браузер.
Чи надсилає сторінка величезну кількість інформації DOM?
Чи є кроки формування макету та відображення зображень ресурсоємними?
Чи відбувається дорога обробка у відповідь на дії користувача?
4. JavaScript
Лише на цьому етапі починають впливати деталі на рівні функцій.
Які операції насправді споживають час процесора?
Які з них виконуються багаторазово?
Які пов’язані з тим, що щойно зробив користувач?
5. Пам’ять
Якщо продуктивність погіршується з часом роботи додатку, варто перевірити пам’ять.
Витоки та неконтрольоване збільшення можуть маскуватися під загальну повільність.
6. Реальний вплив на користувача
Нарешті, пов’яжіть усе, що ви знайшли, із фактичним досвідом користування.
Чи став запуск швидшим?
Чи пошук став прискореним?
Чи покращилась навігація?
Чи став якийсь робочий процес менш складним?
Якщо нічого з цього не змінилося, варто поставити під сумнів, чи була взагалі виявлена справжня проблема.
Бюджети продуктивності корисні — якщо вони пов’язані з реальністю
Це звичайна практика, коли команди встановлюють такі правила:
Розмір пакета JavaScript має бути меншим за 300 КБ.
Це розумна відправна точка, краща, ніж зовсім відсутність обмежень.
Але бюджет, заснований на реальному досвіді, зазвичай є кориснішим:
- Основний контент має відображатися швидко
- Пошук не повинен здаватися дуже повільним
- Навігація має надавати миттєву відповідь
- Ключові сторінки не повинні залежати від послідовності запитів
- JavaScript, необхідний для першої взаємодії, має бути мінімальним
- Великі набори даних не повинні відображатися на екрані одночасно
Ці показники важче перетворити на одне чітке число.
Але вони набагато точніше відображають те, що насправді помічають та що важливо для користувачів.
Показники стають корисними тоді, коли допомагають вам зрозуміти, що насправді відбувається.
Вони стають небезпечними у ту мить, коли досягнення певної цифри стає основною метою.
Пастка оптимізації
Існує тонкий психологічний мотив, який спонукає розробників йти цим шляхом.
Оптимізація чогось здається проявом прогресу.
Ви можете вказати на певні зміни та сказати:
Розмір бандлу зменшено на 14%.
Або вказати на тестування та сказати:
Ця функція тепер виконується на 32% швидше.
Або показати комусь скріншот профілера як доказ.
Ці досягнення приносять задоволення.
Але деякі з найбільш ефективних виправлень продуктивності, чесно кажучи, є нудними.
Відмова від зайвого виклику API не створює захоплюючої демонстрації.
Переробка відповіді сервера також не є привабливою.
Це також не є скороченням ланцюга залежностей.
Це також не є виправленням запиту, який отримує 5 000 рядків, хоча достатньо було б 50.
Це також не є додаванням кешу.
Робота, яку ви уникаєте, зазвичай за своєю природою залишається непомітною.
Саме тому її так легко проігнорувати.
Найкраще покращення продуктивності може призвести до меншого обсягу коду, меншої кількості запитів, меншої кількості обчислень та до того, що взагалі буде менше процесів, які працюють.
Можливо, там не буде нічого, що варто було б сфотографувати.
Просто додаток стає кращим у використанні.
Оптимізація має починатися з доказів
Ось правило, яке варто застосовувати у всіх випадках:
Не оптимізуйте код. Оптимізуйте підтверджені проблеми.
Це не вимагає створення складних процесів інженерії продуктивності для кожної функції, яку ви випускаєте.
Це просто означає збір достатньо доказів, щоб зрозуміти, куди насправді йде час.
Скористайтеся інструментами профілювання.
Використовуйте вбудовані панелі продуктивності браузера.
Зберігайте записи мережевої активності.
Отримуйте дані з телеметрії в умовах реальної експлуатації.
Встановіть моніторинг справжніх користувачів там, де це доцільно.
Тестуйте на пристроях, які відображають вашу реальну аудиторію.
І передусім — відтворіть проблему так, як вона була повідомлена.
Якщо зацікавлена сторона каже, що «панель керування працює повільно», стримуйте бажання одразу переходити до коду компонентів та починати видаляти елементи відображення.
Спочатку з’ясуйте, на що саме посилається термін «повільно».
Чи повільна початкова відповідь сервера?
Чи є проблемою певний виклик API?
Чи занадто великий пакет JavaScript?
Чи займає занадто багато часу парсинг?
Чи є відображення дорогим етапом?
Чи є тривала операція, яка блокує основну схему?
Чи погано працює запит до бази даних?
Чи є причини затримок через накопичення запитів?
Чи браузер просто сидить без дії, чекаючи на щось, що могло б розпочатися раніше?
Чи, можливо, додаток технічно реагує, але не надає користувачеві жодної візуальної інформації?
Виправлення проблем з продуктивністю — це робота детектива.
Це не змагання, хто зможе видалити найбільше JavaScript-коду.
Найкраща оптимізація JavaScript — це можливо, менше JavaScript
Це може здатися дивним твердженням від розробника JavaScript.
Але це стає все важливішим у міру зростання додатків.
Кожен фрагмент коду, який виконується на клієнті, має свою вартість.
Його потрібно завантажувати.
Його може знадобитися парсувати.
Його може знадобитися компілювати.
Він має виконуватися.
Він споживає пам’ять.
Він конкурує з браузером за час відображення контенту.
Він може створювати перешкоди під час взаємодії користувача.
Усе це не означає, що JavaScript за своєю суттю поганий.
Це означає, що будь-які обчислення, які відбуваються на клієнті, мають мати обґрунтування свого існування.
Іноді кращим рішенням є обробка даних на сервері.
Іноді — стрімінг контенту замість його блокування.
Іноді — переміщення логіки повністю на бекенд.
Іноді — впровадження кешу.
Іноді — скорочення обсягу даних, які повертає API.
Іноді — поступове завантаження даних замість їх одночасного завантаження.
Іноді — просто видалення функції, якою ніхто насправді не користується.
А іноді JavaScript, який вже є, абсолютно підходить у такому вигляді.
Головне — припинити автоматично припускати, що оптимізація мусить відбуватися безпосередньо всередині самого JavaScript.
Що зрештою вивчають досвідчені розробники
На початку кар’єри розробника оптимізація зазвичай означає прискорення роботи існуючого коду.
З набуттям більшого досвіду увага зміщується на усунення роботи, яка насправді не була потрібна.
З часом запитання стають глибшими, стосуючись причин існування цієї роботи взагалі.
Це значуща еволюція мислення.
Замість того, щоб запитувати:
Чи можна зробити цей цикл працездатнішим?
Запитання стає таким:
Чому взагалі у браузері обробляється 20 000 записів у цьому циклі?
Замість того, щоб запитувати:
Як можна запобігти повторній відрендеризації цього компонента?
Запитання стає таким:
Чому одна дія викликає зміни у всьому стані сторінки?
Замість того, щоб запитувати:
Як можна зробити цей пакет меншим?
Питання стає таким:
Чому користувач мусить завантажувати цей код перед тим, як робити щось корисне?
Замість того, щоб запитувати:
Як можна зробити цей запит більш ефективним?
Питання стає таким:
Чи взагалі потрібен цей запит?
Саме постановка таких глибших запитань призводить до справді кращої архітектури.
Мета — не швидкий код
Це урок, який займає найбільше часу, щоб справді усвідомити.
Робота над продуктивністю — це не створення найшвидшого можливого JavaScript.
Це створення продукту, який здається достатньо швидким для людей, які ним користуються.
Ці дві мети — не одне й те саме.
Чудово оптимізований алгоритм є марним, якщо користувач змушений чекати дві секунди на запит, який його активує.
Ідеально збережений у пам’яті компонент не допомагає, якщо сторінка відображає 40 компонентів, які користувач навіть не побачить.
Менший розмір пакету не означає автоматично кращої ефективності, якщо додаток все одно блокує основну взаємодію через непотрібні операції.
А покращені показники тестування нічого не значать, якщо жоден реальний користувач не відчуває різниці.
Сьогодні розробники JavaScript мають доступ до більшої кількості технік оптимізації, ніж будь-коли раніше.
Це робить ще важливішим знати, що не варто оптимізувати.
Почніть з акценту на користувачеві.
Визначте справжню затримку.
Правильно її виміряйте.
Відстежуйте її в усій системі, від початку до кінця.
Видаліть усе, що не є необхідним.
Лише тоді можна працювати над прискоренням того, що залишилося.
Ця послідовність має значення.
Тому що найцінніша оптимізація — це не обов’язково та, яка є найбільш технічно вражаючою.
Це та оптимізація, яка змушує користувача взагалі не помічати, що додаток спочатку був повільним.
Пов’язана література
- Native Browser APIs Replacing Popular npm Packages in 2026 — Пояснює, як вбудовані функції JavaScript та CSS, такі як Signals, оператор pipeline, Temporal та Anchor Positioning, замінюють поширені пакети npm.