Реактивне програмування — знахідка для лінивих розробників

💡 Усі статті, обговорення, новини про Front-end — в одному місці. Приєднуйтесь до Front-end спільноти!

Всім привіт! Мене звати Дмитро, я займаюсь фронтенд-розробкою, розбираюсь у сучасних вебтехнологіях та не маю симпатії до тестерів. Я студент, якимось чином знаходжу час на навчання, спорт, фронтенд та навіть можу погуляти сходити :) Сьогодні ми поговоримо про парадигму реактивного програмування, її плюси та мінуси, та чому вона для лінивих.

Чи бувало таке, що ви знайшли геніальне, неперевершене рішення проблеми в коді, все працює, але хтось з команди запитав: «А що, якщо зміниться цей параметр?» І раптом усе, що здавалося простим, перетворилося на клубок проблем, які потребують негайного розплутування.

Саме тут на допомогу приходить реактивне програмування — парадигма (підхід або «стиль» написання програм), яка дозволяє не просто спостерігати за змінами, а й автоматично реагувати на них.

Що таке реактивне програмування

Тут одразу зауваження. Якщо у вас немає розуміння, як працює асинхронність в JavaScript, раджу вам прочитати документацію на MDN (Introducing async JavaScript). Якщо з цим усе ок, то...

Тоді почнемо з нудної теорії :)

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

Зрозуміли щось? Давайте простіше...

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

Основна ідея: ви визначаєте, на що потрібно реагувати, а все інше система бере на себе. Легко! Поїхали далі!

Які переваги реактивного програмування

А переваг тут і справді багато:

  1. Простота обробки асинхронності. Робота з асинхронністю в JS може тягнути за собою: головну біль, стрес, перевтому та депресію. На допомогу приходить реактивне програмування, в якому все набагато простіше: ми визначаємо «потік» (stream), який реагує на події, і код сам по собі буде оновлюватися, коли з’являться нові дані. Просто. Без нервів. І без краплі зайвого коду.
  2. Менше коду для керування станом. Не думаю, що хтось бажає керувати станом вручну. Це як посеред ночі прокидатися та перевіряти, чи заряджається телефон. Замість того, щоб вручну оновлювати значення в коді, реактивне програмування робить це автоматично. Ви лише визначаєте залежності (які елементи залежать від яких), а решта — за реактивною системою. Це економить години коду, і ви не будете повторюватися, як поганий фільм.
  3. Масштабованість. Коли твій маленький пет-проєкт переходить у великий web-застосунок, він стає більшим і вже не є таким зрозумілим, як був спочатку. З’являється більше функцій, логіки, залежностей, за якими потрібно слідкувати. Реактивні системи автоматично обробляють ці залежності, і ви не витрачаєте час на постійне оновлення різних частин програми. Вони працюють завжди ідеально, незважаючи на масштаби проєкту, це дуже круто.

Головні елементи реактивного програмування

  1. Потоки даних (Streams). Це, по суті, асинхронні канали, через які ваша програма отримує та обробляє інформацію. Вони дозволяють робити це, не чекаючи на всі дані відразу, а працюючи з ними поступово, як тільки вони з’являються.
  2. Спостерігачі (Observers). Це особливі об’єкти, які слідкують за всім, що відбувається у потоці даних. Їхня головна мета — бути готовими миттєво реагувати, коли щось змінюється. Це як коли наприкінці місяця перевіряєш картку на зп :)

    Тут уважно! Після створення нашого стріма (через об’єкт Observable) потрібно обов’язково підписатись (subscribe). Без підписки стрім не буде працювати й ви опинитесь у вічному очікуванні.

  3. Оператори (Operators). Це інструменти, які перетворюють звичайну інформацію в щось корисне. Наприклад, ви отримали список чисел, а за допомогою map можете помножити всі числа на два, або ж з filter відібрати лише парні.

Тепер подивимось, як це все можна реалізувати!

Як це працює

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

1. Створення потоку даних

const selectedCity$ = new BehaviorSubject('Kyiv');

BehaviorSubject — це спеціальний тип потоку з бібліотеки RxJS. Він зберігає поточний стан (у нашому випадку обране місто) і дозволяє всім, хто підписаний на цей потік, отримувати актуальне значення.

2. Обробка змін у потоці

selectedCity$
  .pipe(
    switchMap(city => fetchFlightsForCity(city))   )

Що тут відбувається?

pipe — це метод, який дозволяє застосувати декілька операторів до потоку даних, оператори своєю чергою трансформують або обробляють дані. switchMap — це оператор, який:

  1. Отримує поточне значення з потоку (city).
  2. Викликає функцію fetchFlightsForCity(city), яка надсилає HTTP-запит для отримання рейсів цього міста.
  3. Якщо потік змінюється (користувач обрав інше місто), switchMap автоматично скасовує попередній запит і запускає новий.

3. Підписка на потік

.subscribe(flights => updateUI(flights));

subscribe — це метод, який «активує» потік і виконує певну дію з отриманими даними.

У цьому випадку ми отримуємо список рейсів (flights) і передаємо його у функцію updateUI, яка оновлює інтерфейс користувача.

Думаю, тут не все так тяжко, все пізнається через документацію ;)

Рухаємось далі...

Обробка помилок у реактивному програмуванні

Мабуть, у вас з’явилося питання: «Діма, а що в цій параштуці робити з помилками, як обробляти?» Зараз все розповім.

У реактивному підході помилки — це не «кінець світу», а просто ще одна частина потоку. Система, яку ми побудуємо, дозволить грамотно їх обробити, щоб застосунок залишався стабільним навіть у критичних ситуаціях.

Нижче — кілька корисних підходів, які рятують від головного болю.

  1. Перехоплення помилок (catchError). Це як мозок реактивного потоку. Цей оператор сам вирішить, що робити з помилкою: логнути її, повідомити юзера, або, може, перезапустити процес.
import { of, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

const data$ = throwError(() => new Error('Щось пішло не так!')).pipe(
  catchError(error => { // Додаємо мозок до проекту :)
    console.error(error.message); // Логуємо помилку
    return of('Резервні дані'); // Повертаємо резервне дані
  })
);

data$.subscribe(value =>
console.log(value));
  1. Резервні дані (fallback). Теж класний оператор. Якщо система тупить, вона може повернути щось альтернативне. Наприклад, кешовані дані або повідомлення про технічні роботи.
import { of, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

const fetchData$ = throwError(() => new Error('Сервер недоступний')).pipe(
  catchError(() => of('Дані з кешу')) // Повертаємо резервні дані
);

fetchData$.subscribe(value => console.log(value));
  1. Повторення спроб (retry). Гарного провайдера тяжко обрати, а коли ще з відключеннями світла потрібно бігати до кав’ярні по не найкращий інет, взагалі жах.
    import { of, throwError } from 'rxjs';
    import { retry, catchError } from 'rxjs/operators';const unstableRequest$ = throwError(() => new Error('Проблема з мережею')).pipe(
      retry(3), // Повторюємо запит 3 рази
      catchError(error => of(`Запит провалено: ${error.message}`))
    );
    unstableRequest$.subscribe(value => console.log(value));
    

    Тому ми видихаємо та використовуємо оператор retry, але без фанатизму.

  2. Відновлення (resume). У деяких випадках можна продовжити виконання потоку, навіть якщо сталася помилка. Це забезпечує гнучкість і дозволяє обробляти лише критичні помилки, не перериваючи роботу всього застосунку.
    import { of, from } from 'rxjs';
    import { catchError, map } from 'rxjs/operators';const tasks$ = from([1, 2, 'помилка', 4]).pipe(
      map(task => {
        if (task === 'помилка'){ throw new Error('Помилка у потоці!');}
        return task * 2;
      }),
      catchError(() => of('Продовжуємо роботу')));
    tasks$.subscribe(value => console.log(value));
    

    У разі помилки ми не кидаємо всю роботу, а акуратно обробляємо проблему і продовжуємо.

Основні інструменти

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

Інструментів багато, є більш нові, є більш зручні, але я виділю, мабуть, найкращі:

1. RxJS

RxJS — це клондайк для розробників, які хочуть використовувати всі переваги реактивного програмування. Ця бібліотека створена для управління потоками подій, асинхронних операцій і будь-яких змін у даних у реальному часі.

RxJS має величезний набір операторів (map, filter, reduce, merge), які дозволяють легко трансформувати та комбінувати дані.

Розглянемо кейс. Уявіть, є поле пошуку, є проблема — в компанії не дуже сильні сервера. Що робити? Ми можемо щось вигадати на звичайному JS, наприклад:

const searchInput = document.getElementById('search');

searchInput.addEventListener('input', () => {
  setTimeout(() => { // Затримка 300 мс
    console.log(searchInput.value);
  }, 300);
});

Воно буде працювати, але ми задовбаємось контролювати затримку вручну та скасовувати зайві виклики.

Тепер реалізуємо те ж саме з RxJS:

// Імпортуємо необхідні функції з бібліотеки RxJS
import { fromEvent } from 'rxjs'; // Створення потоку подій з DOM-елемента
import { debounceTime, map } from 'rxjs/operators'; // Оператори для роботи з потоками

// Знаходимо елемент поля вводу за його ID
const searchInput = document.getElementById('search');

// Створюємо поток подій для введення тексту у поле
fromEvent(searchInput, 'input') // Слухаємо події "input" на елементі
  .pipe(
    debounceTime(300), // Робимо затримку 300 мс, щоб уникнути частих викликів
    map(event => event.target.value) // Отримуємо значення тексту з події
  )
  .subscribe(value => console.log(value)); // Виводимо значення

Супер, сервера мають надію на життя і тепер бек буде приносити вам ранкову каву :)

2. React + Redux-Observable

React хоч крутий фреймворк, але не є повністю реактивним (гарно написано). Його можна вдосконалити за допомогою інструментів, як-от Redux-Observable. Цей middleware для Redux дозволяє обробляти асинхронні дії у вигляді потоків, що дає змогу реалізувати складну бізнес-логіку.

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

Якщо без Redux-Observable:

const fetchUser = async () => {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Помилка:', error);
  }
};

fetchUser();

Вручну обробляти помилки, слідкувати за запитами, мені це ліньки робити :)

Для лінивих Redux-Observable вирішує це так:

import { ofType } from 'redux-observable'; // Фільтрує потік дій за їх типом
import { switchMap, catchError, map } from 'rxjs/operators'; // Оператори для обробки потоків
import { ajax } from 'rxjs/ajax'; // Використовується для виконання HTTP-запитів
import { of } from 'rxjs'; // Створює нові потоки даних

const fetchUserEpic = (action$) => 
  action$.pipe(
    // Перевіряємо тип вхідної дії, залишаємо тільки дії з типом 'FETCH_USER'
    ofType('FETCH_USER'),
    // Виконуємо HTTP-запит замість вхідної дії
    switchMap(() =>
      ajax.getJSON('https://jsonplaceholder.typicode.com/users/1').pipe(
        // Якщо запит успішний, створюємо новий екшен 'FETCH_USER_SUCCESS'
        map((response) => ({
          type: 'FETCH_USER_SUCCESS', // Тип нової дії
          payload: response, // Дані, отримані із запиту
        })),
        // Якщо виникла помилка, створюємо новий екшен 'FETCH_USER_ERROR'
        catchError((error) =>
          of({
            type: 'FETCH_USER_ERROR', // Тип дії для помилки
            payload: error.message, // Текст помилки додається у payload
          })
        )
      )
    )
  );

export default fetchUserEpic;

Ну, виглядає зашибісь і працює також гарно.

3. Vue.js (реактивність «із коробки»)

Як мені цього не хотілось, але мушу сказати, що тут Vue крутіше за React :(

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

<template>
  <div>
    <p>Значення лічильника: {{ count }}</p>
    <button @click="increment">Додати</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0 // Реактивна змінна
    };
  },
  methods: {
    increment() {
      this.count++; // Автоматично оновлює DOM
    }
  }
};
</script>

Коли ви створюєте змінні у data() або використовуєте ref у Composition API, Vue автоматично відстежує ці змінні, і це не може не вабити.

На JS це було б так:

const countElement = document.getElementById('count');
const button = document.getElementById('increment');

let count = 0;

button.addEventListener('click', () => {
  count++;
  countElement.textContent = `Значення лічильника: ${count}`;
});

Реактивне програмування для всіх?

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

Розповім про проблеми, які можуть виникнути, та як я їх розв’язував:

  • Крива навчання. Коли читав документацію, гортав гугл та думав, куди ж цю парадигму засунути, часом з’явилося велике бажання викинути ноут через кватирку :) Тому будьте готові, що не одразу зрозумієте, навіщо це вам. Почніть із простих прикладів, типу обробки кліків чи запитів до API, всі ми починали з малого. З часом ви зрозумієте, що реактивщина — це не так страшно, як здається.
  • Дебагінг. Тут починається жестяк. У звичайному коді помилку ми знаходимо через console.log. Але коли потік проходить через 10 операторів, а на виході виходить «undefined», починаєш сумувати за часами, коли ти просто верстав звичайні лендінги. Щоб голова не закипіла та життя засяяло кольорами, спробуйте розбити складний потік на менші шматочки. Краще мати 5 маленьких функцій, ніж одну, яку тільки зрозумієш і то завтра забудеш.
  • 💡 Перша конференція DOU Front-end Day 2025
  • Зловживання операторами. Кожен розробник бажає, щоб його код був найкращим. Побачивши нові технології, думає: «А чому б не вставити їх сюди, тут і ще отам?» Але через місяць код перетворюється на незрозумілий хаос, який важко читати, а розуміти взагалі неможливо.
  • Ваш код — купа незрозуміло чого. Ви повинні писати його за таким принципом: «Код читається частіше, ніж пишеться». Ваш колега (або ви самі через три тижні) має зрозуміти, що відбувається. Якщо питання вирішується звичайним map, не треба притягувати switchMap тільки тому, що він звучить крутіше.

Підсумок

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

Також я веду Телеграм-канал, де ви знайдете багато цікавого про JavaScript, фронтенд, корисні інструменти, практичні задачі та кар’єрні поради. Підписуйтесь! 🚀

👍ПодобаєтьсяСподобалось7
До обраногоВ обраному3
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

Ой, дуже вибачаюсь. Але бачив сон, не зовсім зрозумілий та адекватний:
Стою я, тримаю в руці палку, і точно знаю що десь там за дверима стоїть мій кореш і чекає на цю палку, а між нами бігає туди-сюди абізян (наче, зелена макака). Що там на шляху до мого кореша ніхто з нас в душі не знає але палку тре передати, тож кличу абізяна, записую в журнал обліку передачі палок, і з Богом. Абізян бере палку, робить дуже відповідальну гримасу та біжить до кореша. Проходе якийсь час, і він прибігає куди треба. Простягає палку однією рукою до кореша, інша рука вже лізе сама до сумки шукаючи своє заохочення за виконану задачу. Кореш бере палку і бачить що то не палка а ручка від домкрата. На питання, де абізян її взяв та навіщо, де палка та що взагалі трапилось — звісно замість чіткого пояснення абізян знаходить в сумці свою цукерку, та біжить по своїх важливих справах. Коли проснувся, подумав: ну добре хоч щось приніс, в реальності тією палкою ще б вломив мені по шиї. А тут пост про реактивність під’їхав, і щось той сон згадався.

Не стаття, а катування гіфками :) Не розумію, навіщо їх стільки пхати, тим більше, що їхня релевантність, м’яко кажучи, сумнівна :)

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

у мене для Вас є 2 новини:
1-хороша
2-не дуже.

Мені подумалося що ця стаття чудово ілюструю проблеми сучасних JS фреймвоків. Усі вони побудовані на «чудовій ідеї», але ця ідея чудово вирішує тільки один нюанс системи — при цьому про усе інше автор намагається не думати.
Ось тут описана чудова ідея для візуалізації і обробці струму даних. Дані течуть, кожен підписується, бере собі свій шматочок, обробляє, відображає, реагує на зміни ... І усе це можна робити чистими функціями які не зберігають стейт. Завантаження будь якого складного веб — аплікейшина у такий спосіб виглядає як ніби потік крові заповнює кінцівку від найтовстіших судин до найдрібніших капілярів. Красива ідея!
От тільки потім виявляється що данні повинні «текти» не тільки в одному напрямку! Ми швидко «намалювали» ідеальну картинку, якщо приходять нові данні вона міняється — але ми також повинні реагувати на потік подій від користувача чи від окремих елементів нашої системи.
Здавалося б тут також усе має бути просто: сигнали про події ідуть «нагору» по ієрархії елементів, десь обробляються, формується новий потік даних, зміни відображаються.
По аналогії як імпульс нервової системи іде від обпеченого пальця «нагору» у мозок і той спускає команду на яку реагують м’язи аби відсмикнути руку. Знову — красива ідея!
Але на практиці дуже скоро усе це перетворюється на хаос! Чому? Продовжимо нашу аналогію: у нас є потік кольорових кульок і руки, які на них реагують. Прийшла кулька — підкинули у повітря, беремо наступну. Але кульки через деякий час падають назад — і нам знову треба реагувати і встигнути підкинути їх. Пробували колись навчитися жонглювати?
Поки у вас тільки 1 кулька — усе просто, 2 — вже потрібна деяка практика, додаємо третю — і доведеться витратити дні аби навчитися тримати у повітрі усі 3 і не допускати падіння.
А тепер уявіть що це не пет-проєкт, а «професійна» система де жонглювати треба усім одразу: палючими факелами, шаблями, скляними пляшками, важкими предметами...
Тому реальні «реактивні» системи, які я бачив на практиці виглядають так: відбулася одна подія — прокручуються обробники, створюють 10 нових подій — обробники прокручуються 10 разів, просять нові данні, дані приходять — обробники прокручуються знову ... Таким чином навіть на першому завантаженні аплікейшина деякі функції відпрацьовують десятки разів, поки колись увесь потік змін вщухне і стейт стабілізується.
Але далі юзер хоче щось розтягнути бо текст не влазить ... і починається нова хвиля перерахунку розмірів кожного компонента і відповідно перерахунку розмірів сусідніх компонентів ...
Оце і є зворотній бік усієї чудової ідеї реактивного програмування!
— Легко підкинути багато кульок у повітря — важко потім їх усі піймати. Тому дуже часто якщо просто натискати рефреш на таких сайтах — то можна побачити кожен раз різні помилки: щось не встигло завантажитися, інше щось впало бо його очікувало. Це ж асинхронність — тут не вгадаєш яка подія буде наступною.
— А ще як кажуть «в одну ріку не можна увійти двічі»: потік даних постійно міняється через події, а зміни у даних викликають нові події... Це як кинути камінь в калюжу: скільки разів хвилі пройдуть від краю до краю поки нарешті усе вгамується і можна буде знову побачити своє відображення у воді?
— На відміну від фізичних процесів — у віртуальній системі ніхто не гарантує вщухання хвилі змін! Якщо відобразити усі можливі стани та усі можливі події як переходи між ними — то отримаємо так званий «скінченний автомат». І у ньому цілком можливо зайти як у «глухий кут», так і у вічний цикл. Особливо якщо відступити від «золотого шляху», який єдиний тестують і з якого користувачу краще не сходити!
Якщо вважаєте що реактивне програмування — це просто, то просто спробуйте намалювати схему «скінченного автомату» для свого веб — аплікейшина.

так це не просто, але які альтернативи?
для великих і інтерактивних веб аппок я таких не знаю

UI це завжди складно, бо:
На бекенді код\фіча або працює, або не працює.
На «фронтІ» — працює, але:
-«трохи» неправильно,
-повільно
-правильно та швидко, але, тойво, піддайте гламуру, бо щось якось не тойво. Самі зрозумійте, переробіть-покажіть, а ми вам скажемо що доробити.

на бекенді теж є подібні проблеми, крім гламуру і «танців зі шрифтами»

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

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

Не зрозумів чому React не оновлює стан автоматично як Vue на прикладі. Там ж одне і те саме зі state.

радий що після оновлення ангулар-а у нас все менше rxjs і все більше сигналів,
сподіваюсь rxjs випилять (залишив би тільки в реактивних формах)

тоді я без роботи залишусь...

Сигнали це ж просто обгортка (верхнерівнева абстракція або можливо альтернативна імлементація) BehaviorSubject. Для стейт менеджменту.
Так, є ще calculated, але це теж скоріш за все якась доволі розумна обгортка для якого-небудь switchMap.
Можливо я не правий, не працював із Ангуляром кілька років, якщо хтось знає як воно всередині заімплементовано, поділіться будь-ласка, буде цікаво.

В будь-якому разі, сигнали це про стейт і про події його змін. RxJs про обробку всіх подій взагалі. Тобто сигнали це лише підмножина ReactiveX
Події від браузера, дебаунс і тротлінг, складні сценарії комбінації послідовностей — Rx потужний інструмент в цих випадках.

Дякую за статтю

Реактивне програмування ламає мозок на початку. Після імперативного перелаштовуватися досить складно. Плюс воно poisoning і має тенденцію до розповсюдження по коду.

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

Код виходить типу декларативний, але досить важкий для розуміння, особливо коли ми комбінуємо декілька потоків данних. Потоки можуть неявно зберігати стан програми, і це теж додає складності.

ПС Приклад для Vue — не зовсім «реактивний» у сенсі реактивного програмування, хоча може під капотом там воно і є, з приклада це не зрозуміло.

Вітаю! Дякую, що прочитали статтю та за правку по vue!

Вже ж була стаття про RxJS. Невже підвищення треба заробити?

Воно буде працювати, але ми задовбаємось контролювати затримку вручну та скасовувати зайві виклики

що значить «контролювати затримку вручну» і «зайві виклики»? у наведеному прикладі достатньо буквально додати змінну і clearTimeout. Код лишається простим і очевидним.

Супер, сервера мають надію на життя і тепер бек буде приносити вам ранкову каву :)

чому? тільки тому, що уммовний сетТаймаут сховано під капот? обсерваблє-інтерваблє-таймаут-канцеляблє.

Наведені приклади, як на мене, навпаки показують простоту і красоту ванілаЖс порівняно з йет-еназе-лібрару

Доброго вечора! Звичайний JS чудово підходить для простих сценаріїв, і якщо вам достатньо setTimeout + clearTimeout — це теж робоче рішення. Але коли проєкт росте, потоки подій стають складнішими, тут реактивний підхід починає давати вигоду.

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

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

Реактивне програмування це перш за все про розповсюдження сигналів, лише один із підходів до маршрутизації та обробки подій у коді, один із інструментів для реалізації всіляких Publisher-Subscriber/Observer/Mediator патернів. Так, він допомагає керувати локальним стейтом додатку, бо дає змогу розповсюджувати події, якими є зміна даних. Але це тільки один із варіантів застосування, хоча і мабуть один із найвідоміших.

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

Не вказано жодної альтернативи, та немає якогось хоча б мінімального аналізу, переваги/мінуси, в яких випадках краще не використовувати?

Доречі, імплементації та бібліотеки є для багатьох мов/платформ, не тільки RxJs: Rx.NET, RxJava, та інші.

Про тестування жодного слова, а це може бути дуже боляче, особливо коли на сцену виходять time-shifted послідовності та ота мимохідь згадана асинхронність.

Ну і не вказати лінків на базові ресурси для тих хто хоче розібратися глибше, це теж таке собі...
reactivex.io
rxmarbles.com

Доброго вечора! Дякую за ваші правки!

Які є юз кейси де це є бенефітом а не головною біллю?

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

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

схоже по суті на функціональне програмування

формули в екселі. Все існує одночасно, немає глобального «якщо то інакше».
антисамурайщина.

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

особисто мені реактивність того ж реакту схожа саме на таблиці табличного редактора зі значним використанням формул.

Коли в голові треба перелючитися з імперадивного підходу на декларативний.

Все, тепер допер, ще не пив кави зранку ) Дякую за гарну аналогію.

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

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

Інтерактивна мапа подій для ІоТ, із сотнями обʼєктів і тисячами подій на хвилину. Отримує дані через веб-сокети (gRPC, whatever near-RTM), є можливість юзера реагувати на події, змінювати налаштування обʼєктів.
Як би ви це імплементували?

Майже усі приклади на голому js коротші за фреймворкові варіанти.
Для їх розуміння достатньо знання js & webAPI, коли для реалізації на фреймворку треба знати все те ж саме, але додатково сам фреймворк, розуміти його архітектуру, і можливо ще вміти в обов’язкові додаткові скрипти.
На жаль, зі статті не дуже очевидний виграш між підходами та між фреймворками.

Доброго вечора! Дякую за коментар! Ви праві, у багатьох випадках голий JS дійсно коротший, і він не вимагає додаткових знань про фреймворк. Але головна ідея статті — показати, що реактивний підхід дозволяє зменшити ручне керування станом і підвищити масштабованість, що особливо корисно у великих проєктах.

У вас в одному пості поруч стоять слова RxJS та «простота». Але ж це взаємовиключні поняття 🤣

Жодної згадки про сигнали... Стаття запізнилася на років 10.

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