Використання Proxy та Reflect для створення реактивних об’єктів у JavaScript
Реактивність є основою багатьох сучасних фреймворків, таких як Vue.js, Svelte та навіть внутрішніх механізмів React. Вона дозволяє автоматично оновлювати UI, коли змінюється стан.
Одним з найефективніших способів створення реактивних об’єктів у JavaScript є Proxy API та Reflect API. У цій статті ми розглянемо, як вони працюють, чому вони краще за Object.defineProperty, та як їх можна використати для створення власного простого реактивного механізму.
Що таке Proxy та Reflect?
Proxy
Об’єкт Proxy дозволяє перехоплювати операції над іншими об’єктами (наприклад, отримання, встановлення, видалення властивостей) та змінювати їхню поведінку.
const obj = { name: "Alice" };
const proxy = new Proxy(obj, {
get(target, property) {
console.log(`Отримання значення ${property}`);
return target[property];
},
set(target, property, value) {
console.log(`Зміна ${property} на ${value}`);
target[property] = value;
return true;
}
});
console.log(proxy.name);
proxy.age = 25;
Reflect
Reflect – це набір утиліт, який спрощує роботу з об’єктами, даючи змогу безпечно виконувати операції (get, set, deleteProperty тощо).
const obj = { name: "Alice" };
console.log(Reflect.get(obj, "name"));
Reflect.set(obj, "age", 25);
console.log(obj.age);
Reflect часто використовується разом із Proxy, щоб делегувати стандартну поведінку, не переписуючи її вручну.
Чому Proxy краще за Object.defineProperty()?
До появи Proxy для реактивності використовували Object.defineProperty, але цей підхід має обмеження:
Object.defineProperty працює тільки з окремими властивостями, а Proxy дозволяє працювати з цілим об’єктом.
- Неможливо відстежувати додавання/видалення властивостей.
Object.defineProperty не працює з масивами так само ефективно, як Proxy.
Приклад проблеми з Object.defineProperty:
const obj = {};
Object.defineProperty(obj, "name", {
get() {
console.log("Отримання значення");
return "Alice";
},
set(value) {
console.log("Зміна значення");
}
});
obj.name = "Bob";
console.log(obj.name);
delete obj.name;
З Proxy ми можемо легко відстежувати всі зміни.
Створення простого реактивного об’єкта за допомогою Proxy та Reflect
Створимо базовий механізм, який дозволить відстежувати зміни у стані та викликати відповідні функції при оновленні значень.
function reactive(target) {
const subscribers = new Set();
const notify = () => {
subscribers.forEach(subscriber => subscriber());
};
return new Proxy(target, {
get(obj, prop) {
console.log(`Отримання значення ${prop}`);
return Reflect.get(obj, prop);
},
set(obj, prop, value) {
console.log(`Зміна ${prop} на ${value}`);
Reflect.set(obj, prop, value);
notify();
return true;
},
deleteProperty(obj, prop) {
console.log(`Видалення ${prop}`);
Reflect.deleteProperty(obj, prop);
notify();
return true;
},
subscribe(fn) {
subscribers.add(fn);
}
});
}
const state = reactive({ count: 0 });
const render = () => console.log(`Рендер: count = ${state.count}`);
state.subscribe(render);
state.count = 1;
state.count = 2;
delete state.count;
Реактивні масиви через Proxy
Масиви у JavaScript є об’єктами, тому Proxy може працювати з ними аналогічно.
const reactiveArray = reactive([]);
reactiveArray.subscribe(() => console.log("Масив змінено:", reactiveArray));
reactiveArray.push("React");
reactiveArray.push("Vue");
reactiveArray.pop();
Проблема з length у масивах
При видаленні елемента length масиву змінюється, що теж можна перехопити:
const arrayHandler = {
set(target, prop, value) {
console.log(`Зміна ${prop} на ${value}`);
return Reflect.set(target, prop, value);
}
};
const reactiveNumbers = new Proxy([1, 2, 3], arrayHandler);
reactiveNumbers.push(4);
reactiveNumbers.length = 2;
console.log(reactiveNumbers);
Підключення реактивних об’єктів до DOM
Тепер давайте зробимо зв’язок між станом і HTML, щоб створити базову реактивність.
<!DOCTYPE html>
<html lang="uk">
<head>
<title>Реактивний лічильник</title>
</head>
<body>
<p id="counter">Лічильник: 0</p>
<button id="increment">Збільшити</button>
<script>
function reactive(target, render) {
return new Proxy(target, {
set(obj, prop, value) {
obj[prop] = value;
render();
return true;
}
});
}
const state = reactive({ count: 0 }, () => {
document.getElementById("counter").innerText = `Лічильник: ${state.count}`;
});
document.getElementById("increment").addEventListener("click", () => {
state.count++;
});
</script>
</body>
</html>
✅ Що ми зробили?
- Створили реактивний об’єкт
state.
- Підключили його до DOM (текст у
<p id="counter"> змінюється при оновленні count).
- Додали подію
click, яка змінює стан.
🚀 Вийшов міні-VueJS без фреймворків!
Висновок
Proxy та Reflect дають змогу створювати потужні механізми реактивності без зайвих складнощів.
🔥 Що ми дізналися:
✔ Proxy дозволяє перехоплювати всі операції з об’єктами.
✔ Reflect допомагає зручно делегувати стандартну поведінку.
✔ Реактивні об’єкти можна використовувати в UI, автоматично оновлюючи DOM.
✔ Масиви також можна зробити реактивними через Proxy.
💡 Proxy – це основа багатьох сучасних фреймворків, і розуміння його механіки допоможе вам глибше зрозуміти Vue, Svelte та навіть внутрішні механізми React. 🚀
Web3 як заміна Web2 у стандартних завданнях: чи є в цьому сенс?

Світ веб-технологій динамічно змінюється. Якщо Web1 був ерою статичних сайтів, а Web2 — ерою соціальних мереж, централізованих платформ і динамічного контенту, то Web3 пропонує децентралізовану альтернативу, засновану на блокчейні, смарт-контрактах і криптовалютах.
Але чи реально Web3 замінить Web2 у стандартних завданнях, таких як пошук інформації, платежі, зберігання файлів чи управління ідентифікацією? Чи це просто модний тренд без реальних переваг? Давайте розберемося.
Що таке Web3 і в чому його відмінність від Web2?
📌 Web2 – це нинішній інтернет, де більшість сервісів контролюється великими компаніями (Google, Facebook, Amazon). Вони керують нашими даними, контролюють платформи та встановлюють правила гри.
📌 Web3 – це концепція децентралізованого інтернету, де користувачі контролюють свої дані та взаємодіють один з одним без посередників. Основні технології Web3:
✔ Блокчейн – децентралізоване зберігання та перевірка транзакцій.
✔ Смарт-контракти – автоматизовані угоди без потреби в довірених третіх особах.
✔ DApps (децентралізовані додатки) – додатки, що працюють на блокчейні.
✔ Децентралізовані ідентифікації (DID) – методи входу без паролів, через криптовалютні гаманці.
🚀 Головна ідея Web3: ніяких посередників, більше свободи для користувачів.
Але чи це працює в реальних завданнях?
1. Децентралізовані платежі vs. банківські системи
У Web2 всі транзакції проходять через банки, PayPal, Visa або Mastercard. Вони контролюють платежі, можуть блокувати рахунки або стягувати високі комісії.
✅ Web3 рішення:
- Криптовалютні платежі (Bitcoin, Ethereum, USDT) – миттєві та глобальні перекази.
- Stablecoins – криптовалюти, прив’язані до долара, що зменшують волатильність.
- DeFi (децентралізовані фінанси) – кредити, депозити без банків.
❌ Проблеми:
- Високі комісії в Ethereum (але з’являються рішення, як Solana, Polygon).
- Втрата доступу до гаманця = втрата коштів (банки хоча б дозволяють відновити доступ).
- Обмежене прийняття криптовалют у звичайних магазинах.
📢 Вердикт: Web3 поки що не може повністю замінити банківські системи, але криптовалюти можуть бути вигідним доповненням у міжнародних переказах та DeFi-сервісах.
2. Децентралізоване зберігання файлів vs. Google Drive, Dropbox
Зараз більшість користувачів зберігають файли у централізованих хмарах (Google Drive, iCloud, Dropbox).
✅ Web3 рішення:
- IPFS (InterPlanetary File System) – децентралізована мережа для зберігання файлів.
- Arweave, Filecoin – зберігання даних на блокчейні з оплатою за довготривале збереження.
❌ Проблеми:
- Висока вартість у порівнянні з централізованими хмарними сховищами.
- Швидкість доступу до файлів у Web3 нижча, ніж у Google Drive.
- Потрібні криптовалютні гаманці для оплати зберігання.
📢 Вердикт: Web3-зберігання має потенціал, але поки що Web2 рішення швидші, дешевші та зручніші для масового користувача.
3. Децентралізовані соцмережі vs. Facebook, Twitter
Централізовані соцмережі контролюють контент, можуть блокувати користувачів, продають дані рекламодавцям.
✅ Web3 рішення:
- Lens Protocol, Mastodon, Steemit – децентралізовані платформи, де дані контролюють користувачі.
- NFT-профілі – ідентифікація без паролів.
❌ Проблеми:
- Мало користувачів → немає масового ефекту.
- Важко монетизувати контент без традиційної реклами.
- Повна децентралізація може спричинити проблеми з модерацією контенту.
📢 Вердикт: Web3-соцмережі ще не готові замінити Facebook та Twitter, але вони можуть стати нішевими альтернативами.
4. Децентралізовані ідентифікації vs. Google Login, Facebook Login
Зараз люди реєструються на сайтах через Google чи Facebook, віддаючи свої дані компаніям.
✅ Web3 рішення:
- Ethereum Name Service (ENS) – унікальні Web3-імена замість паролів.
- Decentralized Identifiers (DID) – цифрові ідентифікації, які не залежать від корпорацій.
❌ Проблеми:
- Втрата приватного ключа = втрата доступу до всіх акаунтів.
- Потрібен криптовалютний гаманець для автентифікації.
📢 Вердикт: Web3-ідентифікація цікава, але Google/Facebook авторизація залишається зручнішою для більшості користувачів.
Чи є сенс у повному переході з Web2 на Web3?
🔹 Web3 має переваги у безпеці, конфіденційності та децентралізації, але він ще не готовий повністю замінити Web2.
🔹 Більшість Web3-рішень повільніші, дорожчі та складніші у використанні для масового ринку.
🔹 Проте Web3 додає альтернативу, дозволяючи користувачам обирати між централізованими та децентралізованими сервісами.
Що буде далі?
💡 Web2 і Web3, ймовірно, співіснуватимуть – Web2 залишиться основою для звичайних користувачів, а Web3 буде активно використовуватись у фінансах, цифровій ідентифікації та зберіганні цінних даних.
🚀 Web3 – це не заміна Web2, а його доповнення.
Можливо, через 10 років ми навіть не помітимо, як Web3 стане стандартом у багатьох сферах, але поки що він проходить стадію активного розвитку.
Висновок
| Завдання |
Web2 рішення |
Web3 альтернатива |
Чи варто переходити? |
| Платежі |
Банки, PayPal |
Криптовалюти, DeFi |
✅ Якщо потрібні миттєві глобальні транзакції |
| Зберігання файлів |
Google Drive, Dropbox |
IPFS, Arweave, Filecoin |
❌ Поки що Web2 дешевше та швидше |
| Соцмережі |
Facebook, Twitter |
Lens, Steemit |
❌ Web3-соцмережі ще не готові |
| Ідентифікація |
Google Login |
ENS, DID |
✅ Якщо потрібно більше приватності |
Web3 – це потужний тренд, але поки що він не готовий повністю замінити Web2.
Проте, як тільки децентралізовані сервіси стануть простішими, швидшими та дешевшими, майбутнє інтернету може змінитися назавжди. 🚀
Як трейдерську стратегію “Черепах” використовують на криптовалютному ринку?

Криптовалютний ринок відомий своєю високою волатильністю, різкими ціновими коливаннями та нестабільністю. Для ефективного трейдингу тут важливо використовувати чіткі правила входу та виходу з позицій, щоб мінімізувати ризики та отримати максимальний прибуток. Одна з найвідоміших стратегій, яка успішно працювала на традиційних фінансових ринках, – “Стратегія черепах” (Turtle Trading Strategy).
Ця стратегія була розроблена ще у 1980-х роках для ф’ючерсних ринків, але чи працює вона у світі криптовалют? У цій статті ми розглянемо основні принципи стратегії черепах, її адаптацію для цифрових активів, а також конкретні приклади її застосування на Bitcoin, Ethereum та інших криптовалютах.
Що таке стратегія “Черепах”?
Стратегія “Черепах” була створена Річардом Деннісом та Вільямом Екхардтом, які хотіли довести, що трейдинг – це навик, якому можна навчитися. Вони відібрали групу людей без досвіду у фінансах, навчили їх певним правилам торгівлі і через рік отримали професійних трейдерів, які успішно заробляли на ринку.
Основні принципи стратегії “Черепах”:
- Вхід у ринок – позиції відкриваються при пробої ключових рівнів (наприклад, 20-денного або 55-денного максимуму).
- Вихід із ринку – позиції закриваються при зворотному пробої рівнів або при досягненні стоп-лосу.
- Ризик-менеджмент – кожна угода не повинна перевищувати певного відсотка від загального капіталу (1-2%).
- Дисципліна – стратегія має жорсткі правила, що виключають емоційні рішення.
Чому стратегія називається “черепахами”?
Річард Денніс порівнював трейдерів зі зростанням черепах у фермерському господарстві – якщо забезпечити їм правильні умови, вони будуть рости та приносити прибуток. Тому він навчав трейдерів як “вирощувати” прибуткові угоди.
Чи працює стратегія “Черепах” на криптовалютному ринку?
Криптовалютний ринок суттєво відрізняється від традиційних ринків:
- Вища волатильність – Bitcoin може змінювати свою ціну на 10-20% за день, що рідко трапляється з акціями чи ф’ючерсами.
- Ринок працює 24/7 – на відміну від фондового ринку, тут немає торгових сесій, тому пробої рівнів можуть траплятися в будь-який момент.
- Маніпуляції – на малих активах є ризик “фальшивих пробоїв”, коли великі гравці штучно змушують ціну рухатись у певному напрямку.
Проте ключові принципи “Черепах” все ще залишаються ефективними, якщо їх правильно адаптувати під реалії криптовалют.
Як адаптувати стратегію “Черепах” для криптовалют?
1. Визначення пробою рівнів
Класична стратегія використовувала 20-денні та 55-денні рівні для входу.
✅ Адаптація для крипторинку:
- 10-денний пробій – для короткострокових угод.
- 50-денний пробій – для довготривалих позицій.
🔹 Приклад:
Якщо Bitcoin пробиває 50-денний максимум, це сигнал для входу в лонг (купівлю). Якщо пробиває 50-денний мінімум – це сигнал для шорт-позиції (продажу).
python
import pandas as pd
def turtle_signal(data, period=50):
data['High_Max'] = data['High'].rolling(period).max()
data['Low_Min'] = data['Low'].rolling(period).min()
data['Buy_Signal'] = data['Close'] > data['High_Max'].shift(1)
data['Sell_Signal'] = data['Close'] < data['Low_Min'].shift(1)
return data
2. Управління ризиками
✅ ATR (Average True Range) для визначення стоп-лосса
ATR – це індикатор, який вимірює волатильність ринку.
📌 Як встановити стоп-лосс?
Правило: Стоп-лосс = Вхідна ціна – (ATR * 2)
python
def calculate_stop_loss(entry_price, atr, risk_factor=2):
return entry_price - (atr * risk_factor)
✅ Зменшення розміру позиції на високій волатильності
Якщо ринок “штормить”, краще зменшити обсяг угоди, щоб не отримати величезний збиток.
3. Використання трейлінг-стопу
Якщо тренд продовжується, вигідно використовувати трейлінг-стоп, щоб фіксувати прибуток, не виходячи з ринку завчасно.
📌 Як це працює?
Якщо ціна росте, стоп-лосс “рухається” за нею.
Якщо ціна падає до встановленого рівня – позиція закривається.
Реальні приклади використання стратегії “Черепах” у криптотрейдингу
1. Bitcoin (BTC/USD) – довгострокова стратегія
- Квітень 2021: Bitcoin пробив 50-денний максимум (~$60,000) – сигнал на купівлю.
- Травень 2021: ціна зросла до $64,000, після чого було зафіксовано трейлінг-стопом прибуток.
2. Ethereum (ETH/USD) – короткострокова стратегія
- Листопад 2022: ETH пробив 20-денний рівень, трейдер зайшов у лонг.
- Ціна зросла на 15% – трейлінг-стоп зафіксував прибуток.
Плюси та мінуси стратегії “Черепах” у криптотрейдингу
✅ Переваги:
✔️ Добре працює у трендових ринках.
✔️ Прозорі правила входу та виходу.
✔️ Дисципліна та відсутність емоційного трейдингу.
❌ Недоліки:
❌ Багато фальшивих пробоїв у флеті.
❌ Необхідність жорсткого управління ризиками.
❌ Ринок 24/7 – потрібні автоматизовані алгоритми.
Висновок
Стратегія “Черепах” може працювати у криптовалютній торгівлі, якщо адаптувати її під високу волатильність та швидкі зміни ринку.
🔹 Якщо ринок трендовий – стратегія приносить прибуток.
🔹 Якщо ринок флетовий – потрібні додаткові фільтри, щоб уникати зайвих входів.
Головне правило – дисципліна. Саме вона зробила “черепах” успішними трейдерами у 1980-х, і саме вона допоможе вам заробляти у криптовалютах сьогодні! 🚀
Топ-5 бібліотек для керування станом у React

Керування станом у React — одна з ключових тем для розробників, оскільки додатки стають дедалі складнішими, а їхня архітектура потребує продуманих рішень. Незважаючи на вбудований useState і useReducer, у багатокомпонентних додатках часто виникає необхідність централізованого керування станом. У цій статті ми розглянемо топ-5 бібліотек для керування станом у React, їхні особливості, переваги та коли їх варто використовувати.
1. Redux – класика глобального стану
🌟 Коли використовувати:
- Великі проєкти, де важливо зберігати та контролювати зміни стану.
- Коли потрібен суворий контроль над даними та можливість відстеження змін.
- Коли є багато взаємопов’язаних компонентів, які потребують доступу до спільного стану.
🔹 Основні особливості:
- Централізований стор (store) – весь стан зберігається в єдиному сховищі.
- Чисті редюсери – зміни вносяться через функції, що не змінюють поточний стан напряму.
- Middleware (наприклад,
redux-thunk або redux-saga) дозволяють керувати асинхронними запитами.
🔸 Мінуси:
- Велика кількість “бойлерплейту” (багато коду навіть для простих операцій).
- Висока складність для новачків.
🔹 Приклад Redux у дії:
import { createStore } from 'redux';
const initialState = { count: 0 };
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
};
const store = createStore(counterReducer);
export default store;
import { useSelector, useDispatch } from 'react-redux';
const CounterComponent = () => {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
return (
<div>
<p>{count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>-</button>
</div>
);
};
2. Zustand – мінімалістичний стейт-менеджер
🌟 Коли використовувати:
- Коли потрібна легка альтернатива Redux без зайвого коду.
- Коли ви хочете керувати станом без громіздких редюсерів.
- Ідеально підходить для невеликих проєктів або управління локальним станом.
🔹 Основні особливості:
- Простий API, що не вимагає створення редюсерів.
- Підтримка асинхронних дій без middleware.
- Прямий доступ до стану без потреби в селекторах чи провайдерах.
🔸 Мінуси:
- Менша екосистема, ніж у Redux.
- Може бути не найкращим вибором для великих додатків.
🔹 Приклад використання:
import create from 'zustand';
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
const CounterComponent = () => {
const { count, increment, decrement } = useStore();
return (
<div>
<p>{count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
};
3. Recoil – нативний стейт-менеджер від Meta
🌟 Коли використовувати:
- Коли потрібна потужна альтернатива Redux з меншими витратами.
- Для проєктів, які працюють з деревоподібними структурами стану.
🔹 Основні особливості:
- Використання атомів (мінімальних одиниць стану).
- Асинхронні селектори, що дозволяють легко працювати з даними з API.
- Глибока інтеграція з React Suspense.
🔸 Мінуси:
- Поки що перебуває у фазі розробки та не є стандартом.
- Деякі особливості не підтримуються старими версіями React.
🔹 Приклад використання:
import { atom, useRecoilState } from 'recoil';
const countState = atom({
key: 'countState',
default: 0,
});
const CounterComponent = () => {
const [count, setCount] = useRecoilState(countState);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
</div>
);
};
4. Jotai – суперлегкий та реактивний стейт-менеджер
🌟 Коли використовувати:
- Для невеликих проєктів, які потребують гнучкого керування станом.
- Коли хочете щось простіше, ніж Recoil, але з подібною концепцією.
🔹 Основні особливості:
- Прямий доступ до стану без складної структури.
- Використання атомів (як у Recoil).
- Нативна підтримка асинхронних операцій.
🔸 Мінуси:
- Менша підтримка в спільноті.
- Потребує глибшого розуміння реактивних структур.
🔹 Приклад використання:
import { atom, useAtom } from 'jotai';
const countAtom = atom(0);
const CounterComponent = () => {
const [count, setCount] = useAtom(countAtom);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
</div>
);
};
5. React Query – для роботи з серверним станом
🌟 Коли використовувати:
- Коли потрібно ефективно працювати з запитами до API.
- Якщо додаток потребує кешування даних і оновлення при зміні бекенду.
🔹 Основні особливості:
- Автоматичне кешування даних.
- Фонове оновлення при зміні фокусу або повторних запитах.
- Мінімізація запитів до сервера.
🔸 Мінуси:
- Використовується для роботи зовнішніх даних, а не локального стану.
🔹 Приклад використання:
import { useQuery } from '@tanstack/react-query';
const fetchUsers = async () => {
const res = await fetch('https://jsonplaceholder.typicode.com/users');
return res.json();
};
const UsersList = () => {
const { data, error, isLoading } = useQuery(['users'], fetchUsers);
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error loading users</p>;
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
Обирайте бібліотеку відповідно до завдань вашого проєкту! 🚀
Способи поділу тривалих завдань у JavaScript

JavaScript — це однопотокова мова програмування, що працює на основі event loop (циклу подій). Це означає, що виконання складних або тривалих обчислень може заблокувати головний потік, зробивши додаток непрацездатним (UI перестане відповідати, а користувачі побачать “зависання”). Тому вкрай важливо правильно ділити тривалі завдання, щоб не порушувати плавність роботи застосунку.
У цій статті ми розглянемо основні способи розбиття довготривалих завдань у JavaScript, їхні переваги та недоліки.
Проблема блокування головного потоку
Веб-додатки працюють у середовищі, де кожна задача виконується в основному потоці. Якщо якийсь код займає надто багато часу (наприклад, складні обчислення або обробка великої кількості даних), це блокує подальше виконання подій, включаючи анімації, введення користувача та відповіді на HTTP-запити.
Приклад проблеми:
function longTask() {
let sum = 0;
for (let i = 0; i < 1e9; i++) {
sum += i;
}
console.log("Task completed", sum);
}
longTask();
console.log("Цей код виконається лише після завершення довгої задачі.");
Результат:
- Браузер “зависає” на кілька секунд.
- Жодна інша подія не може бути виконана.
Як цього уникнути? Ось кілька основних способів.
1. Використання setTimeout або setInterval
Одним із простих способів розділити виконання тривалих завдань є розбиття задачі на менші частини та виконання їх у наступних ітераціях циклу подій.
Приклад:
function longTaskChunked() {
let sum = 0;
let i = 0;
function processChunk() {
let start = Date.now();
while (i < 1e9) {
sum += i;
i++;
if (Date.now() - start > 50) {
console.log("Chunk processed");
setTimeout(processChunk, 0);
return;
}
}
console.log("Task completed", sum);
}
processChunk();
}
longTaskChunked();
Переваги:
- Не блокує основний потік.
- Користувач може продовжувати взаємодіяти з UI.
Недоліки:
- Не дає реального багатопотокового виконання.
- Витрати на перемикання контексту можуть уповільнювати виконання.
2. Використання requestIdleCallback
Функція requestIdleCallback дозволяє виконувати задачі, коли браузер має вільний час, тобто між основними подіями.
Приклад:
function longTaskIdle(deadline) {
let sum = 0;
let i = 0;
function processChunk() {
while (i < 1e9 && deadline.timeRemaining() > 0) {
sum += i;
i++;
}
if (i < 1e9) {
requestIdleCallback(processChunk);
} else {
console.log("Task completed", sum);
}
}
requestIdleCallback(processChunk);
}
longTaskIdle();
Переваги:
- Виконується тільки тоді, коли браузер не зайнятий.
- Не впливає на продуктивність анімацій та взаємодію з UI.
Недоліки:
requestIdleCallback не гарантує виконання задачі в певний час.
- Не працює в старих браузерах (Safari не підтримує).
3. Використання Web Workers (багатопотоковість)
Web Workers дозволяють виконувати задачі у фоновому потоці, повністю уникаючи блокування головного потоку.
Головний файл (main.js):
const worker = new Worker("worker.js");
worker.onmessage = function (e) {
console.log("Result from worker:", e.data);
};
worker.postMessage(1e9);
Файл Web Worker (worker.js):
self.onmessage = function (e) {
let sum = 0;
for (let i = 0; i < e.data; i++) {
sum += i;
}
self.postMessage(sum);
};
Переваги:
- Реальне багатопотокове виконання.
- Не блокує UI.
Недоліки:
- Web Worker не має доступу до DOM.
- Додаткові накладні витрати на передачу повідомлень.
4. Використання yield у Generator функціях
Генератори (function*) дозволяють створювати “паузи” у виконанні функції, які можна контролювати.
Приклад:
function* longTaskGenerator() {
let sum = 0;
for (let i = 0; i < 1e9; i++) {
sum += i;
if (i % 1e6 === 0) yield;
}
return sum;
}
const task = longTaskGenerator();
function processNext() {
const result = task.next();
if (!result.done) {
setTimeout(processNext, 0);
} else {
console.log("Task completed", result.value);
}
}
processNext();
Переваги:
- Дозволяє виконувати довгі завдання поетапно.
- Гнучкий контроль над виконанням.
Недоліки:
- Виконання все ще однопотокове.
- Синтаксис може бути незручним для великих задач.
Висновок
У JavaScript є кілька підходів до розбиття тривалих завдань:
| Метод |
Блокування UI |
Багатопоточність |
Застосування |
setTimeout / setInterval |
❌ Ні |
❌ Ні |
Дрібні задачі, нескладна обробка |
requestIdleCallback |
❌ Ні |
❌ Ні |
Фонові задачі без чітких дедлайнів |
| Web Workers |
❌ Ні |
✅ Так |
Тяжкі обчислення, незалежні задачі |
yield + Generator |
❌ Ні |
❌ Ні |
Гнучке управління процесом |
Що вибрати?
- Якщо потрібно просто розбити задачу на частини без блокування UI — використовуйте
setTimeout.
- Якщо задача не термінова і може виконуватися, коли браузер “відпочиває” —
requestIdleCallback.
- Якщо потрібна реальна паралельність (обробка відео, складні обчислення) — Web Workers.
- Якщо треба контролювати процес поступового виконання — генератори (
yield).
Головне — правильний вибір інструменту, адже неправильне використання може призвести до зайвих витрат ресурсів або складнощів у підтримці коду.
Сподіваюся, ця стаття допомогла вам краще розібратися у темі! 🚀
SSL та SSL-сертифікати для новачків

Безпека в інтернеті — це одна з ключових тем, яку не можна ігнорувати. Якщо на сайті передаються важливі дані (наприклад, паролі або платіжна інформація), то безпечний канал зв’язку є критично важливим. SSL (Secure Sockets Layer) і його наступник — TLS (Transport Layer Security) забезпечують захищене з’єднання між клієнтом (браузером) та сервером. У цій статті пояснимо, що таке SSL, чому потрібні SSL-сертифікати та як усе це працює на практиці.
Що таке SSL
SSL (Secure Sockets Layer) — це криптографічний протокол, який створює захищений канал передачі даних через інтернет. Починаючи з певного часу, SSL-технологія була вдосконалена й формально змінилася на TLS. Однак у щоденному вжитку говорять “SSL” та “TLS” майже як синоніми. Принцип полягає у шифруванні даних та взаємній автентифікації учасників з’єднання, щоб третя сторона (зловмисник) не змогла їх прочитати чи підробити.
Навіщо потрібні SSL-сертифікати
Щоб браузер і сервер домовилися про безпечний канал, потрібен “секрет” — сертифікат, що підтверджує, що даний сервер — дійсно той, за кого себе видає. Користувач бачить “замочок” у адресному рядку (https://) і може бути впевненим, що з’єднання зашифроване.
Типові причини, чому SSL-сертифікати стали стандартом:
-
Захист даних
Усі дані (паролі, повідомлення, платіжна інформація), що передаються між клієнтом і сервером, стають зашифрованими. Зловмисник, який перехопить трафік, побачить лише набори зашифрованих байтів.
-
Автентифікація сайту
Сертифікат містить інформацію про домен, організацію, якій цей домен належить. Якщо сертифікат відповідає домену, браузер довіряє з’єднанню.
-
Поліпшення SEO
Починаючи з певного часу, Google краще оцінює сайти, доступні через HTTPS, у рейтингу пошуку.
Як працює SSL/TLS
-
Handshake
- Клієнт (браузер) підключається до сервера за допомогою HTTPS.
- Сервер відправляє свій SSL-сертифікат клієнту.
- Браузер перевіряє, чи сертифікат не прострочений, чи відповідає домену, чи підписаний довіреним центром сертифікації (CA).
-
Створення сесійного ключа
- Якщо сертифікат дійсний, браузер і сервер узгоджують “сесійний ключ” (симетричний ключ).
- Далі трафік шифрується цим ключем.
-
Захищене з’єднання
- Усі дані надсилаються зашифрованими з використанням алгоритмів (наприклад, AES).
- Стороння особа, яка перехопить пакет даних, не зможе його розшифрувати без ключа.
Різновиди SSL-сертифікатів
- Self-signed (самопідписані)
- Ви можете створити сертифікат власноруч, але браузери не довірятимуть йому “з коробки”. Вони попереджатимуть про “небезпечне” з’єднання. Це підходить для локальної розробки.
- DV (Domain Validation)
- Перевіряється власність домену (адміністратор підтверджує, що він справді контролює домен). Найпростіший у отриманні.
- OV (Organization Validation)
- Додатково перевіряються документи й дані про компанію, яка замовляє сертифікат. Браузер зазвичай показує ім’я організації.
- EV (Extended Validation)
- Найбільший рівень перевірки. Колись дозволяв відображати “зелений рядок” у браузері. Зараз більшість браузерів змінили UI, але ідея лишилась: EV підтверджує повну юридичну інформацію про організацію.
Як отримати SSL-сертифікат
- Безкоштовні (Let’s Encrypt)
- Let’s Encrypt видає безкоштовні DV-сертифікати. Треба налаштувати автоматичне оновлення (кожні 90 днів). Для більшості сайтів вистачає цього.
- Платні CA
- Компанії (GlobalSign, Digicert, Sectigo) пропонують DV, OV, EV-сертифікати. Платні варіанти дають кращий захист, репутацію, страхування від шахрайства.
Встановлення сертифіката на сервер
- Отримати ключ (private key) і сам сертифікат (public key).
- Налаштувати веб-сервер (Nginx, Apache, Node.js) вказати, де розміщено private key, де сертифікат.
- Перевірити перезапуск сервера і перейти за https:// ваш_домен.
Приклад (Nginx)
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/ssl/certs/cert.pem;
ssl_certificate_key /etc/ssl/private/key.pem;
location / {
proxy_pass http://localhost:3000;
}
}
Node.js (HTTPS)
const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();
const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
https.createServer(options, app).listen(443, () => {
console.log('HTTPS server running on port 443');
});
Як використовувати SSL у локальній розробці
- Self-signed сертифікат
- Можна створити через openssl, але браузер видаватиме попередження.
- mkcert
- Зручний інструмент, що створює локальний “власний” CA і ставить його в довірені у вашій системі. Це прибирає попередження.
- Docker Compose з Traefik або іншими реверс-проксі.
- Можна підняти реверс-проксі, що має “перехоплювати” HTTP-запити і видавати самопідписаний сертифікат.
HTTPS і HTTP/2
Якщо ви вже налаштували TLS, варто розглянути HTTP/2, адже більшість браузерів вмикають HTTP/2 лише при використанні https. HTTP/2 дає мультиплексування, що покращує продуктивність (кілька запитів можуть оброблятися одночасно в межах одного TCP-з’єднання).
Поширені помилки
- Неправильний CN чи SAN.
- Якщо домен не збігається із зазначеним у сертифікаті, браузер попереджає про небезпечне з’єднання.
- Закінчився термін сертифіката.
- Потрібно поновлювати сертифікат вчасно (Let’s Encrypt кожні 90 днів).
- Старі протоколи (SSLv3, TLSv1.0).
- Рекомендується вимикати застарілі протоколи і шифри, залишивши сучасні TLSv1.2 чи v1.3.
- HTTP-змішаний контент.
- Якщо сторінка сама https, а деякі ресурси (картинки, скрипти) завантажуються через http, браузер може заблокувати їх або видавати попередження.
Висновок
SSL (точніше TLS) — фундаментальний механізм захисту даних, який гарантує шифрування й перевірку автентичності домену. Без нього сучасний веб важко уявити, бо весь обмін конфіденційними даними був би небезпечним. Сертифікати можна отримати безкоштовно (Let’s Encrypt) або придбати розширені опції (OV, EV) для більш серйозних проєктів. Налаштування SSL-сертифіката не складне: достатньо згенерувати ключі, налаштувати веб-сервер і переконатись, що домен відповідає конфігурації. У результаті отримуєте https-з’єднання (замочок), підвищений рівень довіри, кращий рейтинг у пошуку та захист даних від прослуховування й атак посередника.
IPC у Node.js: як вирішити проблему з передачею даних між процесами

Node.js – це середовище виконання JavaScript, яке, попри однопоточну архітектуру, здатне обробляти велику кількість одночасних з’єднань. Однак бувають ситуації, коли додатку потрібно скористатися додатковим процесом, щоби, наприклад, розпаралелити ресурсоємну задачу, обробити складні обчислення чи забезпечити ізоляцію. У таких випадках актуальною стає проблема обміну даними між процесами. Ця стаття присвячена різним механізмам IPC (Inter-Process Communication – взаємодія між процесами) у Node.js, а також тому, як вони вирішують задачу “зшивання” даних між різними частинами застосунку.
Чому важливо мати IPC у Node.js
- Розподіл навантаження
Основний процес Node.js часто бажано тримати “легким” і віддавати ресурсоємну роботу іншим процесам. Наприклад, генерація PDF, опрацювання відео, складні алгоритми.
- Ізоляція
Якщо виникає помилка в одному процесі, це не “кладе” весь додаток.
- Масштабування
Кілька процесів можуть використовувати доступні CPU-ядра ефективніше, ніж одне.
- Безпека
Відокремлюючи частини логіки (наприклад, мікросервіси), знижуєте ризик критичного збою.
Основні методи IPC у Node.js
Child processes (child_process.fork)
Node.js має вбудовану можливість створювати дочірні процеси для виконання коду. Коли використовується fork(), створений процес має “канал” для обміну повідомленнями з батьківським процесом за допомогою process.send() і child.on('message').
Приклад – просте спілкування між parent.js і child.js.
child.js:
process.on('message', (msg) => {
console.log('Child received:', msg);
process.send({ reply: 'Hello from child' });
});
parent.js:
const { fork } = require('child_process');
const child = fork('./child.js');
child.on('message', (msg) => {
console.log('Parent got message:', msg);
});
child.send({ text: 'Hi child' });
Важливо, що fork() виконує новий JavaScript-файл у окремому процесі, дозволяючи паралельні обчислення і незалежний контекст, а також channel для повідомлень.
Worker Threads
Починаючи з Node.js v10.5, з’явився модуль worker_threads, який дозволяє створювати Worker. Вони запускаються у тому самому процесі, проте мають окремий event loop, окрему пам’ять (хоча можна використовувати SharedArrayBuffer). Перевага в тому, що передача об’єктів часто є швидшою, ніж при child_process, і немає overhead створення повноцінного окремого процесу.
Приклад worker.js:
const { parentPort } = require('worker_threads');
parentPort.on('message', (data) => {
parentPort.postMessage(`Worker processed: ${data}`);
});
Головний файл:
const { Worker } = require('worker_threads');
const worker = new Worker('./worker.js');
worker.on('message', (msg) => {
console.log('From worker:', msg);
});
worker.postMessage('Hello from main thread');
Cluster
Cluster – це модуль, що дозволяє “клонуати” процес Node.js на декілька робочих (worker) процесів, які використовують одну “слухаючу” порт програму. Підходить для створення “pool” процесів, що приймають HTTP-запити, розподіляючи навантаження на всі CPU-ядра.
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker) => {
console.log(`Worker ${worker.process.pid} died, forking a new one.`);
cluster.fork();
});
} else {
http.createServer((req, res) => {
res.writeHead(200);
res.end(`Handled by worker ${process.pid}\n`);
}).listen(3000);
}
IPC у cluster
Всі робочі процеси можуть обмінюватись повідомленнями з майстер-процесом (через event worker.on('message')), а майстер може відправляти повідомлення назад worker.send(msg). Це зручно, коли потрібно зберігати якісь глобальні дані, які синхронізуються поміж процесами.
ZeroMQ, Redis та інші “зовнішні” варіанти
Якщо у вас складна система мікросервісів, Node.js-процеси можуть взагалі не обмежуватись єдиним хостом. Тоді ефективно застосовувати зовнішній брокер повідомлень (Redis Pub/Sub, RabbitMQ, Kafka). Це переходить із рівня локального IPC до рівня мережевого, проте концептуально виконує схожу функцію — обмін даними між процесами.
Порівняння
- Child processes – простий підхід, коли треба “відокремити” якийсь скрипт від основного коду або викликати інший файл у Node. Взаємодія через .send() / on(‘message’).
- Worker Threads – більш “легка” паралелізація усередині одного процесу, зручна для ресурсомістких обчислень. Передача даних через повідомлення, можна навіть використовувати SharedArrayBuffer.
- Cluster – корисний для швидкого масштабування HTTP-сервера на всі CPU-ядра. Керує автоматичним створенням воркерів, а майстер-процес може розподіляти запити.
- Зовнішні брокери – якщо додаток розподілений на багато вузлів чи хочемо “відмовостійку” мікросервісну архітектуру.
Приклади, коли потрібен IPC
- Відеообробка
Припустимо, є веб-додаток, що приймає відеофайл і має виконати його стискання. Основний процес Node виконує лише прийом і передачу файлу у дочірній процес (child_process), який запускає ffmpeg. Потім повертається результат.
- Аналітика
Основний HTTP-сервер обслуговує запити, а статистику/аналітику “зливає” у воркер, щоб не блокувати головний цикл.
- Кешування
Коли є кілька воркерів (Cluster), і вони мають синхронізувати інформацію про кеш, можна відправляти повідомлення майстер-процесу, який розсилає їх усім іншим воркерам.
Поради з оптимізації
- Не пересилайте великі об’єкти JSON занадто часто — це створює накладні витрати. Можливо, варто передавати лише ID або ключі, а не весь масив даних.
- Якщо працюєте із Worker Threads, зверніть увагу на SharedArrayBuffer чи Transferable Objects, щоб не дублювати пам’ять.
- Не забувайте обробляти помилки. Якщо дочірній процес аварійно “падає”, потрібно перезапустити його (або принаймні логувати помилки).
- У cluster можна “запам’ятовувати” статистику (процесів, що впали), щоб уникати нескінченного циклу перезапусків.
Висновок
IPC у Node.js дозволяє писати більш потужні та масштабовані застосунки, оскільки перерозподіляє завдання поміж кількома процесами чи потоками. Вибір інструменту залежить від вашого сценарію:
- Child processes — коли треба запустити окремий скрипт.
- Worker Threads — паралельні обчислення без overhead створення процесів.
- Cluster — щоб використати всі ядра CPU для одного HTTP-додатка.
- Зовнішні брокери (Redis, ZeroMQ) — коли система мікросервісів є розподіленою.
Правильне налаштування IPC, врахування безпеки, перезапуску при помилках та ефективне передавання даних — все це складається у архітектуру Node-додатків, що можуть обробляти значні навантаження та лишатися стабільними.
Боротьба з перерендерами у React: збереження продуктивності UI

React дозволяє створювати інтерфейси, які оновлюються лише тоді, коли дані справді змінюються. Але на практиці трапляються випадки, коли компоненти рендеряться знову й знову, навіть без реальної потреби. Це може знижувати продуктивність, спричиняти “пригальмовування” та сповільнювати відгук додатка. У цій статті зібрано ключові прийоми та концепції, які допоможуть вам ефективно боротися з надлишковими перерендерами і зберігати високу швидкодію UI.
Чому перерендери важливі
React працює за принципом Virtual DOM, порівнюючи попередній стан з новим та оновлюючи інтерфейс лише там, де відбулися зміни. Але якщо компонент “вважає”, що змінився його проп або стан, відбувається повторний рендер. Якщо таких повторів багато, UI може почати гальмувати. Особливо це помітно у великих таблицях, списках або багаторівневих компонентах.
Типові причини надлишкових рендерів
-
Анонімні функції та об’єкти у пропсах
Кожного разу при рендері батьківський компонент створює нове посилання (наприклад, () => setState(…)), яке React бачить як “зміна пропів” у дочірнього компонента.
-
Зміна контексту (Context)
Коли в контексті оновлюється навіть одне поле, всі компоненти, які його споживають, можуть перерендеритися.
-
Відсутність мемоізації
Якщо підкомпоненти не “захищені” за допомогою React.memo або PureComponent, вони можуть рендеритись навіть при незначних змінах у батьківському компоненті.
-
Фальшиві оновлення стану
Коли викликається setState з тим самим значенням (наприклад, setCount(count)), React теж ініціює рендер (хоча він може оптимізувати, якщо ви користуєтесь певними підходами).
Інструменти аналізу
-
DevTools Profiler
Chrome DevTools (Performance) або профайлер у React DevTools дають змогу побачити, які компоненти рендеряться і скільки часу це займає.
-
why-did-you-render
Спеціальна бібліотека, яка вказує у консоль, коли React виконує перерендер компонента і чому він вважає, що пропи змінились.
Мемоізація компонентів
React.memo
Для функціональних компонентів існує React.memo, який проводить поверхневе порівняння пропів:
const MyComponent = React.memo(function MyComponent(props) {
console.log('Render MyComponent');
return <div>{props.value}</div>;
});
Якщо props.value не змінився (поверхнево), MyComponent не буде ререндеритися. Проте це працює лише, якщо пропи є простими (числа, рядки). Для об’єктів чи масивів, які завжди створюються заново, React.memo не допоможе без додаткових прийомів.
useCallback і useMemo
Якщо передаємо у пропсах функції чи складні об’єкти, бажано використовувати useCallback і useMemo, щоб React “запам’ятав” (мемоізував) значення. Наприклад:
function Parent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => setCount(c => c + 1), []);
return <Child onClick={increment} />;
}
Тепер onClick завжди має те саме посилання на функцію, і якщо Child обгорнуто в React.memo, він не ререндеритиметься при зміні count (якщо на інші пропи це не впливає).
Оптимізація контексту
Якщо контекст (React Context) містить багато даних або часто змінюється, кожен Consumer може ререндеритися. Один зі способів:
- Розділити контекст на кілька “вужчих” контекстів, щоб при зміні певної частини не рендерились інші споживачі.
- Або використовувати useContext в поєднанні зі спеціальними техніками (наприклад, select функціями) чи бібліотеками (react-tracked), які відстежують конкретні поля, що змінилися.
Захист від “фальшивих” оновлень
Перевірка стану перед викликом setState
function Parent() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(prev => {
if (prev === 100) return prev;
return prev + 1;
});
};
return <button onClick={increment}>{count}</button>;
}
У такому разі, якщо поточний стан уже 100, ми не викликаємо непотрібний рендер.
Використання бібліотек
Immer чи valtio
Для складних даних у стані можна використовувати такі бібліотеки, щоб грамотно робити immutable-оновлення, не створюючи “зайвих” нових об’єктів. Це зменшує ризик випадкових перезаписів, що провокують ререндер.
MobX
MobX автоматично “прив’язує” компоненти до певних спостережуваних (observable) полів. Якщо поле не змінювалося, компонент не ререндериться. Проте це вимагає додаткових архітектурних рішень, а також знання MobX.
Поради та шаблони
Split Rendering
Якщо у батьківському компоненті є багато дочірніх, краще “розділити” логіку так, щоб дочірні компоненти отримували тільки ті пропи, які їм дійсно потрібні. Таким чином, якщо змінюється якась глобальна змінна, яку не використовує конкретний дочірній компонент, він не рендериться.
Використання List (для списків) із memo та key
Якщо у вас є довгий список (наприклад, відображення сотень чи тисяч елементів), зверніть увагу на:
- Правильне встановлення key для кожного елементу.
- Мемоізацію кожного рядка (якщо він не залежить від глобальних змін).
- Можливо, потрібно застосувати “віртуальний список” (react-window чи react-virtualized), щоб малювати тільки видимі елементи.
Контрольний список
- Використовуйте React.memo для компонентів, які отримують пропи, що нечасто змінюються.
- Мемоізуйте об’єкти й функції через useCallback та useMemo, щоб уникати створення нових посилань.
- Розділяйте контекст (Context) на менші частини, щоб оновлення стосувалось лише тих компонентів, які дійсно мають змінитись.
- Перевіряйте “фальшиві” оновлення стану (не викликайте setState, якщо немає реальних змін).
- Використовуйте інструменти аналізу: React DevTools Profiler, why-did-you-render.
- Розглядайте віртуалізацію списків, коли працюєте з великими масивами даних.
Висновок
Зайві перерендери у React можуть “з’їдати” продуктивність, але є багато способів боротися з ними. Головне — зрозуміти, чому відбуваються ці повторні рендери: чи це через передачу функцій-анонімок, великих об’єктів у пропсах, чи, можливо, контекст оновлюється надто часто. Правильне використання React.memo, useCallback, useMemo, архітектурне розділення стану, оптимізація контексту — усе це зменшить кількість непотрібних рендерів. У підсумку, користувачі отримають швидкі й чуйні інтерфейси, а код стане більш передбачуваним і зручним у підтримці.
Як прискорити завантаження сайту: гайд для розробників

Час завантаження сайту часто є вирішальним чинником для користувачів: якщо сторінка вантажиться надто довго, відвідувач може просто піти. Це безпосередньо впливає на конверсії, SEO та загальний досвід користувачів. Тож “як прискорити завантаження сайту?” — питання, яке хвилює багатьох розробників. У цій статті зібрано найважливіші поради та прийоми, які можна легко реалізувати у будь-якому веб-проєкті.
Оптимізація зображень
-
Вибір правильного формату
- Якщо потрібна прозорість, підійде PNG, але якщо зображення фотографічне — JPEG або WebP.
- WebP часто дає менший розмір при збереженні якості, хоча деякі старі браузери можуть не підтримувати його.
-
Стиснення
- Застосовуйте інструменти на кшталт ImageOptim або TinyPNG, щоб автоматично зменшувати розмір.
- Можна налаштувати стиснення прямо в CI/CD, щоб розробники не робили це вручну.
-
Ледаче завантаження (lazy loading)
- Замість того, щоб завантажувати усі зображення одразу, підвантажуйте їх, коли вони з’являються у видимій частині екрана.
- Для цього використовується атрибут loading=“lazy” у HTML5 або спеціальні бібліотеки.
Зменшення кількості HTTP-запитів
-
Об’єднання файлів (bundling)
- Якщо у вашому проєкті багато файлів .js і .css, краще об’єднати їх у кілька більших файлів. Це знизить кількість запитів до сервера.
- Сучасні збирачі (webpack, Rollup, Parcel) роблять це автоматично.
-
Використання CDN
- Статичні ресурси (шрифти, бібліотеки, зображення) можна зберігати й віддавати через Content Delivery Network.
- Це дає швидший відгук для користувачів із різних регіонів.
-
Попереднє завантаження (preload, prefetch)
- Якщо ви знаєте, що наступна сторінка вимагатиме певних ресурсів, можна скористатися техніками <link rel=“prefetch”> або <link rel=“preload”>.
- Це допоможе почати завантаження критичних файлів завчасно.
Мінімізація CSS і JS
-
Мінімізація
- Видалення пробілів, коментарів та ін. часто реалізується збирачем (webpack, Gulp, Grunt).
- Метод .min.js і .min.css є стандартом у продакшені.
-
Вилучення невикористаного коду
- Якщо ви підключили велику бібліотеку, але використовуєте лише кілька її функцій, варто застосувати tree shaking (для JS) чи purge (для CSS, наприклад у Tailwind).
- Це може відчутно скоротити вагу файлу.
Кешування
-
Кеш заголовки (cache headers)
- Віддаючи статичні файли, сервер може встановлювати заголовки Cache-Control. Наприклад, Cache-Control: max-age=31536000 для зображень, що не змінюються.
- Якщо файл оновлюється, змінюйте його ім’я (версію), щоб браузер завантажив нову версію.
-
Service Worker
- Для прогресивних веб-додатків (PWA) можна використовувати Service Worker, щоб кешувати файли локально, зменшуючи час завантаження при наступних відвідуваннях.
Ледаче завантаження скриптів
-
Динамічне підключення
- Якщо деякі JavaScript-скрипти не потрібні одразу (наприклад, аналітика, інтерактивні модулі), можна завантажувати їх після того, як основний контент відрендерився.
- Використовуйте атрибути defer чи async для <script>.
- defer виконує скрипти після того, як HTML розібраний; async виконує без блокування потоку HTML, але порядок скриптів може змінюватись.
-
Code splitting
- Сучасні збирачі дають змогу динамічно підвантажувати частини коду: якщо користувач не перейшов у певний розділ, код для нього не завантажується.
- Це зменшує початковий час завантаження.
Шрифти
- Використання сучасних форматів (WOFF2)
- Шрифти у форматі WOFF2 стискаються краще, ніж старі TTF чи WOFF1.
- Відображення fallback
- Можна налаштувати CSS так, щоб під час завантаження шрифту тимчасово відображався системний шрифт. Це запобігає “мерехтінню” порожнього тексту.
Серверна оптимізація
- Gzip чи Brotli стиснення
- Сервер (Nginx, Apache чи інший) може автоматично стискати HTML, CSS і JS перед надсиланням. Це суттєво зменшує розмір відповіді.
- HTTP/2 чи HTTP/3
- Перехід на HTTP/2 (або навіть HTTP/3) може знизити затримки і покращити багатопоточність запитів.
- Використання SSR (Server Side Rendering)
- Якщо у вас React/Angular/Vue, можливість SSR дає змогу відправляти готовий HTML, прискорюючи час першого відображення контенту.
Аналіз швидкодії
- Lighthouse (Chrome DevTools)
- Дає звіт про продуктивність, поради щодо оптимізації.
- GTmetrix, Pingdom
- Онлайн-сервіси, що вимірюють час завантаження сторінки, надають звіт з конкретними рекомендаціями.
- WebPageTest
- Детальна аналітика, скриншоти по секундах, показники first byte, DOMContentLoaded, тощо.
Типові помилки
- Надмірний обсяг зображень чи відео без стиснення
- Підключення великих бібліотек (наприклад, jQuery з цілим набором плагінів) без реальної потреби
- Завантаження безлічі шрифтів, коли досить двох-трьох
- Відсутність кешування чи неправильні cache headers
- Пропущені атрибути defer чи async для JS
Висновок
Прискорення завантаження сайту — це багатоаспектне завдання. Часто розпочинають із оптимізації зображень та мінімізації ресурсів (CSS, JS), налаштування кешу. Потім переходять до тонших прийомів, таких як lazy loading, code splitting, використання CDN і коректного налаштування сервера (HTTP/2, Gzip). Важливо постійно моніторити швидкодію та стежити за рекомендаціями інструментів на кшталт Lighthouse. Правильна оптимізація дасть вашому сайту швидший старт, кращий досвід для користувачів та позитивний вплив на SEO.
Docker для Laravel: як спростити середовище розробки та розгортання

Laravel давно вважається одним із найпопулярніших фреймворків для PHP завдяки його простоті, структурі і великій спільноті. Проте одна з ключових проблем у проєктах на Laravel — це налаштування середовища, особливо якщо розробники працюють на різних операційних системах. Docker дає змогу створювати уніфіковані середовища для розробки та продакшену, значно спрощуючи життєвий цикл додатка. У цій статті розглянемо, як працювати з Docker для Laravel, з чого почати та як налагодити процес розгортання.
Чому Docker важливий для Laravel
-
Уніфіковане середовище
Якщо один розробник працює на Linux, інший на Windows, а третій на macOS, виникають різні нюанси налаштування PHP, бази даних і розширень. Docker виключає такі конфлікти, адже всі запускаються в однакових контейнерах.
-
Легке масштабування
Для продакшен-середовища можна швидко підняти кілька контейнерів з різними компонентами: Nginx/PHP-FPM, Redis, MySQL. Це робить додаток більш гнучким для навантажень і розподілення сервісів.
-
Зручне оновлення середовища
Якщо потрібна інша версія PHP або якесь нове розширення, змінюють Dockerfile, а потім перезбирають контейнер. Не треба ручного “відловлювання” несумісностей.
-
CI/CD інтеграція
Docker гарно інтегрується з інструментами безперервної інтеграції і деплою, адже один і той самий образ можна запускати в розробці, на тест-середовищі і в продакшені.
Приклад базового Docker-середовища для Laravel
Найпростіший варіант — використати офіційні образи PHP (з розширеннями) і MySQL/Redis. Але зручніше мати docker-compose.yml, де буде описано всі сервіси.
docker-compose.yml
version: "3.9"
services:
app:
build:
context: .
dockerfile: Dockerfile
image: laravel-app
container_name: laravel_app
volumes:
- ./:/var/www/html
ports:
- "8000:80"
depends_on:
- db
db:
image: mysql:8
container_name: laravel_db
environment:
MYSQL_DATABASE: laravel_db
MYSQL_ROOT_PASSWORD: secret
MYSQL_USER: laravel
MYSQL_PASSWORD: secret
ports:
- "3306:3306"
- app: описує контейнер з додатком Laravel
- db: контейнер з MySQL
Dockerfile
# Залежить від PHP-образу з фреймворком
FROM php:8.1-fpm
# Встановлюємо додаткові розширення (gd, pdo, etc.)
RUN apt-get update && apt-get install -y \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
# Composer
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/html
# Виставляємо права доступу
RUN chown -R www-data:www-data /var/www/html
# За замовчуванням php-fpm буде слухати 9000 порт
EXPOSE 80
CMD ["php-fpm"]
Пояснення
- Використовується офіційний образ
php:8.1-fpm.
- Встановлюємо необхідні розширення для Laravel (pdo_mysql, mbstring та ін.)
- Додається composer для встановлення залежностей.
- WORKDIR вказує, що всі операції всередині контейнера будуть у
/var/www/html.
Після того, як ми маємо docker-compose.yml і Dockerfile, у корені проєкту (там, де папка з Laravel) можна запустити
docker-compose build
docker-compose up -d
Тепер у браузері можна перейти на http://localhost:8000 і побачити Laravel.
Налаштування .env Laravel для підключення до бази
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel_db
DB_USERNAME=laravel
DB_PASSWORD=secret
Тут DB_HOST=db означає ім’я сервісу з docker-compose.
Робота з файлами і папкою проєкту
Зверніть увагу, що у docker-compose.yml використовується
volumes:
- ./:/var/www/html
Це означає, що локальна папка відображена у контейнері як /var/www/html. Усі зміни, які ви робите локально (редагування файлів Laravel), автоматично відображаються у контейнері, тож немає потреби ребілдити контейнер.
Оптимізації
Виготовляйте окремі Dockerfile для development і production.
- У dev-версії ми можемо робити live reload, mount локального коду.
- У production образі додаток копіюється всередину контейнера, встановлюються залежності, і тоді вміст статичний.
Cache для композитора
Якщо залежності встановлюються часто, оптимізуйте шари Dockerfile так, щоб composer install кешувався, якщо composer.json не змінюється.
Приклад виробничого Dockerfile (Production)
FROM php:8.1-fpm as builder
RUN apt-get update && apt-get install -y \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/html
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader
COPY . .
RUN php artisan config:cache
FROM php:8.1-fpm
COPY --from=builder /var/www/html /var/www/html
WORKDIR /var/www/html
CMD [\"php-fpm\"]
Структура
- builder створює додаток: встановлює залежності, виконує composer install.
- кінцевий образ містить лише результати з builder. Це зменшує розмір образу і полегшує деплой.
Переваги Docker для Laravel
- Узгодженість середовища.
Не потрібно думати, у когось PHP 7.4 чи 8.1, які розширення встановлені. Все прописано у Dockerfile.
- Легке підключення сервісів.
База даних MySQL, Redis, Queue — усе запускається docker-compose, ніяких конфліктів портів і версій.
- Масштабування.
Коли треба запустити кілька контейнерів Laravel, зробити балансування, це робиться порівняно просто.
- CI/CD.
Налаштування конвеєрів (pipeline), де на кожному етапі збирається Docker-образ, запускаються тести, а потім деплой у продакшен.
Підводні камені
- Продуктивність.
На Windows чи macOS, якщо папка проєкту шариться з контейнером, швидкість файлів може бути меншою, ніж на Linux.
- Вчимося Docker.
Розробникам, які ніколи не користувалися контейнерами, доведеться освоїти нові команди, принципи роботи з мережами, volume, build.\n3. Розмір образу.
Якщо без оптимізації, образи можуть бути великі. Варто застосовувати “стислі” базові образи (наприклад, Alpine).
Висновок
Docker дає змогу зробити процес розробки Laravel проєктів більш передбачуваним і контрольованим. Замість витрачати час на ручне налаштування PHP, розширень і СУБД, ми описуємо все у Dockerfile і docker-compose.yml, а потім просто запускаємо контейнери. Це особливо корисно, коли команда розробників велика або коли потрібно швидко відтворити середовище для тестування чи продакшену. Незважаючи на початкові труднощі, переваги (універсальність середовища, масштабованість, легкість деплою) роблять Docker для Laravel гарним вибором.