Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 5
×

Мій список помилок в Angular, яких повинні уникати розробники

Вітаю! Мене звати Олексій Куракін, я працюю в компанії Zazmic Angular/Node розробником вже 2 роки. Я почав програмування на Angular ще у коледжі, спочатку просто «грався», а потім на ньому ще й диплом написав.

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

Я зібрав п’ять, на мою думку, найкритичніших моментів. Буду вдячний, якщо доповните у коментарях своїми прикладами.

1. Логіка, що дублюється

Розглянемо приклад: тобі як програмісту дали задачу написати програму, яка описує різних супергероїв та наділяє їх тими чи іншими суперздібностями. Ти починаєш їх описувати в компонентах (наприклад, ‘supermanComponent’, ‘homelanderComponent’) і розумієш, що у Супермена та у Хоумлендера є однакова здібність — «стріляти лазером з очей».

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

2. Відписуватися від Observables

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

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

Тому варто не забувати: «якщо підписався на потік — то треба і відписатися від потоку». Для цього є кілька способів:

  • найочевидніший — це Unsubscribe. Просто відписатися від потоку при деструктуризації компонента;
  • інший варіант — Rxjs оператор take(), у якому можна вказати, скільки разів ми хочемо отримати дані з потоку. Наприклад, якщо написати take(1), то наш потік стане звичайним промісом;
  • також можна скористатися Async Pipe, якщо ми хочемо передати якусь асинхронну дату в якийсь дочірній елемент. Ця функція бере потік і повертає останнє значення, яке передавалося, а після деструктуризації компонента автоматично відписується від підписки.

3. Витік пам’яті

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

Це може відбуватися через незакритий потік в компоненті, який перерендерується, наприклад, кожної секунди. Очевидно, що вже через кілька хвилин він створить таку кількість потоків, що це заб’є нам усю пам’ять. Тому не забувайте використовувати unsubscribe.

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

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

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

Наприклад: є Бетмен і є Супермен, і вони вирішили «підписатися» на подію, коли хтось буде грабувати банк. Виходить, що коли значення перемінної isBankRobberyActive буде true, вони одночасно отримують зміни і зможуть одночасно вилетіти на місце злочину та з притаманною їм легкістю перемогти злочинців.

4. Написати такий код, що не читається

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

Тобто якщо ви напишете щось типу такого коду array.map(i => ++i).filter(j => j).reduce(k => k, 0) в один рядок, то це справді круто, але розробник, якому через кілька місяців доведеться дивитися на цей код, точно не подякує вам.

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

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

5. Намагатися уникати реактивних форм

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

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

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

Це усе, чим я хотів би поділитися з вами. Дякую за увагу та сподіваюся, що це було корисним. Чекаю на ваші коментарі!

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

Хотів би звернути увагу на те, що у вас у статті зроблено декілька неправильних висновків.
1) Логіка, що дублюється. Посил в цілому правильний, але логіку можна виносити не тільки в сервіси, але й створювати шарені компоненти і наслідуватись від них
2) Відписуватися від Observables. В 99% відсотків випадків, новачки використовують observable для роботи з http викликами (HttpClient), так ось, будь-який викликами
get\post\put\delete і т.д. після виконання викличе відразу complete, і потік закриється сам. Єдиний варіант коли потрібно відписуватись від таких колів, це коли у вас
довгі запити на сервер і ви хочете їх закенселити, в такому випадку unsubscribe автоматично відмінить ваш запит.
3) +
4) +
5) +

Я б додав наступні пункти.
1) Поставте і налаштуйте prettier + linter щоб весь код був одного стилю і з мінімум помилок
2) Мінімізуйте перебивання стилів через !important
3) Мінімізуйте використання функцій в темплейтах. Приклад:
{{ getSubtitle() }}
Просто поставте виклик console.log і подивіться скільки раз у вас викликається така функція
4) Використовуйте по максимуму changeDetection: ChangeDetectionStrategy.OnPush для всіх presentation components
5) Не робіть обробку для кожного елемента списку, особливо якщо він великий. Робіть один обробник на парент.

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

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

Так звісно) дякую що згадали

— не туліть observables та subjects всюди тільки тому що можете. Працюю в проекті, де практично в кожному компоненті є behaviour subject, який отримує дані з сабджекта в іншому компоненті чи сервісі або з @input() і потім з нього зроблена observable, яка вже використовується в решті коду компоненту. То є пекло. Якщо можна обійтися без них — то точно треба писати без них

Альтернатива тогда какая в передаче между компонентами?

Це він і є) причому часто бачу що люди використовують сабджекти не за призначенням, напр. всюди behaviourSubject з початковим значенням null, бо насправді початкове значення логікою фічі не передбачене. Тай таке)

Якщо технологія складна або ви її не до кінця розумієте — це не означає що вона погана.

А можете навести приклад альтернативи щоб передавати дані між компонентами? Просто те що ви описали, це дефакто стандарт коли потрібно розділяти архітектуру на smart\presentational components blog.angular-university.io/...​when-to-use-each-and-why Мені здається,що ви просто не до кінця розумієте, навіщо це використовується на проекті, але це ніяк не робить підхід неправильним.

@Input() + ngOnChanges (без сеттера і сабджекта); метод в смарт-компоненті, який повертає емітовані значення свого сабджекта дочірнім підписникам(без сабджекта та observables в них, достатньо просто підписатись на цей метод)

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