Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як виникає backpressure?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)Backpressure виникає, коли Writable-потік не встигає обробляти дані з тією швидкістю, з якою Readable-потік їх генерує, і внутрішній буфер Writable (обмежений `highWaterMark`) заповнюється - тоді `.write()` повертає `false`, і Node.js призупиняє читання. **Ключове:** повільний запис на диск, стиснення чи шифрування в Transform-потоках і синхронна логіка в `_write()` - типові причини, що посилюють backpressure.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Коротке нагадування визначення **Backpressure (зворотний тиск)** - це ситуація, коли **споживач (Writable)** не встигає обробляти дані з тією швидкістю, з якою **виробник (Readable)** їх генерує. ## Ключова причина виникнення Невідповідність швидкостей потоків: | Потік | Що робить | Можлива проблема | |---|---|---| | `Readable` | генерує дані (наприклад, читає файл, мережу, базу) | надто швидко | | `Writable` | приймає й записує дані (наприклад, пише у файл, HTTP, базу) | надто повільно | Коли `Writable` не встигає, його внутрішній буфер **заповнюється**. І тоді Node.js **зупиняє читання** з джерела, щоб не "залити" систему даними. ## Як це виглядає "усередині" Кожен Writable Stream має **внутрішній буфер** (`highWaterMark`). Приклад: ```javascript const stream = fs.createWriteStream('out.txt', { highWaterMark: 16 * 1024 }); ``` Тут `highWaterMark = 16 KB` - ліміт, скільки даних потік може тримати в буфері. Коли ти викликаєш: ```javascript const ok = stream.write(chunk); ``` то: - якщо буфер не переповнений → `ok = true` - якщо буфер **переповнений** → `ok = false` А це і **є момент виникнення backpressure**. Це сигнал: «стоп, не пиши більше, поки я не звільнюся». ## У який момент це відбувається Схематично: ```javascript Readable (виробляє 100 КБ/сек) ↓ Writable (встигає записувати 30 КБ/сек) ↓ Буфер Writable переповнюється → backpressure ``` У цей момент: 1. `.write()` повертає `false`; 2. Node.js призупиняє читання (`readable.pause()`); 3. Коли Writable скидає буфер на диск → подія `drain`; 4. Node.js відновлює читання (`readable.resume()`). ## Приклад, де backpressure виникає явно ```javascript const fs = require('fs'); const readable = fs.createReadStream('big.txt'); const writable = fs.createWriteStream('copy.txt', { highWaterMark: 1024 }); // буфер 1 KB readable.on('data', (chunk) => { const ok = writable.write(chunk); console.log('Пишемо...', ok ? 'ОК' : 'Буфер переповнений!'); if (!ok) { readable.pause(); // призупиняємо читання writable.once('drain', () => readable.resume()); } }); readable.on('end', () => writable.end()); ``` Тут `writable.write()` повертає `false`, коли потік не встигає - це і є **момент виникнення backpressure**. ## У ланцюжках потоків (`pipe()` і `pipeline()`) Якщо ти використовуєш: ```javascript readable.pipe(transform).pipe(writable); ``` то Node.js робить те саме автоматично: - якщо `writable` повертає `false` → читання зупиняється; - щойно `drain` - читання відновлюється. Тобто **backpressure вбудований у систему pipe()** і не потребує ручного контролю. ## Фактори, що посилюють backpressure | Причина | Приклад | |---|---| | Повільний запис на диск | HDD, мережеві сховища | | Стиснення чи шифрування в Transform-потоках | `zlib`, `crypto` | | Повільний відгук сервера під час HTTP-запису | `res.write()` повільніший за читання | | Великий розмір чанків чи малий `highWaterMark` | надто швидке накопичення буфера | | Складна синхронна логіка в `_write()` | блокує event loop | ## Візуалізація процесу ```javascript ┌────────────────────────────────┐ │ Readable Stream │ └──────────────┬─────────────────┘ │ ▼ Буфер Writable (16 KB) ┌──────────────────────────────┐ │ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │ ← заповнений └──────────────────────────────┘ │ write() → false (Backpressure!) │ ↓ чекати drain() → resume() ``` ## Коротко й просто > Backpressure виникає тоді, > коли **Writable Stream не встигає обробляти вхідні дані**, > і повідомляє Readable Stream, щоб той **призупинився**, > поки буфер не звільниться. ## Як із цим боротися - Використовувати `pipe()` чи `pipeline()` - вони **автоматично** керують backpressure - Налаштувати `highWaterMark` під свою задачу - Робити Transform-потоки ефективними й неблокуючими - Уникати синхронних операцій усередині потоківДля рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.