П’ять шаблонів завантаження даних для підвищення швидкодії сайтів
Фреймворки вам потрібні не для всього, але у разі їх використання є низка способів, що дозволяють досягти максимальної швидкодії. У цій статті йдеться про п’ять шаблонів завантаження даних, які при доречному застосуванні дозволять значно підвищити продуктивність додатків або сайтів.
Коли справа доходить до швидкодії, обмежувати себе не варто. У мережі існують мільйони сайтів, і ви перебуваєте у тісному суперництві з усіма учасниками пошукової видачі Google. Дослідження показало, що користувачі схильні залишати сайти, що завантажуються довше трьох секунд. Три секунди – це небагато. І хоча сьогодні багато ресурсів завантажуються менше, ніж за секунду, жодне рішення не універсальне, і перший запит користувача може стати для вашої програми визначальним.
Сучасні фронтенд-додатки стають дедалі більше. Не дивно, що промисловість серйозно спантеличилася питанням оптимізації. При використанні фреймворків ми отримуємо неадекватні розміри програми, які можуть піти йому не на користь, а на шкоду. Будь-який необов’язковий фрагмент JavaScript, який ви збираєте та відправляєте у продакшен, у результаті лише збільшить кількість коду, який клієнту потрібно завантажити та обробити. Тут чергове правило каже — що менше, то краще.
Шаблони завантаження даних є найважливішою частиною вашої програми, оскільки визначають, які його частини є безпосередньо доступними для відвідувачів. Не створюйте сайт, який гальмуватиме у клієнтів через необхідність завантажити зображення розміром 5МБ на головній сторінці. Намагайтеся краще зрозуміти принципи. Вам потрібно добре розібратися у водоспаді завантаження ресурсів.
Перебір зі спіннерами завантаження та водоспад даних
Водоспад завантаження даних – це каскад файлів, які завантажуються з мережного сервера клієнтом для завантаження вашого сайту від початку до кінця. Він по суті описує життєвий цикл кожного файлу, який ви завантажуєте з мережі для завантаження вашої сторінки.
Наочно подивитися це можна, відкривши браузер і зазирнувши у вкладку Network інструментів розробника на прикладі Medium.
Тут у нас два важливі компоненти:
Графік показує тимчасову лінію кожного запрошеного і завантаженого файла. Тут ви бачите, які файли йдуть першими, і можете простежити кожен послідовний запит до моменту, коли завантаження файлу займає тривалий час. Далі цей файл можна проінспектувати та з’ясувати, чи є можливість його оптимізувати.
Внизу сторінки можна перевірити, скільки КБ ресурсів споживає ваш клієнт. Важливо, скільки даних клієнту необхідно завантажувати. При першій спробі цю інформацію можна використовувати як бенчмарк для подальших оптимізації.
Ніхто не любить спостерігати порожній білий екран, особливо ваші користувачі. При затримці завантаження ресурсів необхідний тимчасовий плейсхолдер, який бачитиме користувач до моменту, коли ви зможете почати створювати макет на стороні клієнта. Як правило, в якості його можна використовувати спіннер або скелетний завантажувач. У процесі поступового завантаження даних сторінка демонструватиме завантажувач, доки всі компоненти не будуть готові для відображення.
І хоча додавання таких плейсхолдерів є покращенням, зайва тривалість їхнього показу також може зашкодити. Справа в тому, що якщо ваша програма надмірно затримується на стадії завантаження, то нехай це і краще порожньої HTML-сторінки, така ситуація все одно дратує, схиляючи відвідувачів залишити сайт.
Але хіба очікування даних не є зрозумілим?
Так, але їхнє завантаження можна прискорити.
Припустимо, що ви хочете завантажити макет соціальної мережі. У цьому випадку ви можете додати спіннер або скелетний завантажувач, щоб унеможливити відображення непромальованого сайту. Скелетний завантажувач зазвичай чекатиме наступного:
даних від API бекенда;
створення макета згідно з цими даними.
Спочатку ви здійснюєте асинхронний виклик до API, потім отримуєте URL-адресу ресурсу в CDN і тільки після цього можете почати створювати макет на клієнтській стороні. Це чимало роботи, коли потрібно показати ваше обличчя, ім’я, статус та пости Instagram відразу.
П’ять важливих шаблонів завантаження даних
Розробляти програмне забезпечення стає все простіше, оскільки фреймворки на кшталт React, Vue або Angular дозволяють з легкістю створювати найпростіші програми. Однак використання цих громіздких інструментів, заповнених купою всіляких функцій, які ви навіть не використовуєте, не варто розглядати як оптимальне рішення.
Ви тут щоб оптимізувати. Пам’ятайте, що менше, тим краще.
Але якщо можливості зменшити обсяг даних у вас немає? Як забезпечити високу швидкість виконання коду? Що ж, тут вам допоможуть п’ять корисних шаблонів завантаження даних, які дозволять прискорити роботу сайту.
Рендеринг на стороні сервера та Jamstack
У сучасних JS-фреймворках відображення сторінок найчастіше реалізується на клієнтській стороні (CSR). Браузер отримує у вигляді корисного навантаження JS-бандл та статичний HTML, після чого малює DOM, а також для реактивності додає слухачів та активатори подій. Коли така програма відображається в DOM, сторінка блокується до завершення цього процесу. Рендеринг робить програму реактивною. Для його виконання необхідно зробити ще один виклик API до сервера та вийняти всі необхідні дані.
У свою чергу, малювання на стороні сервера (SSR) передбачає передачу програмою простого HTML клієнту. SSR можна розділити на два типи: з гідратацією та без гідратації. SSR – це стара техніка, яка використовується такими фреймворками, як WordPress, Ruby on Rails та ASP.NET. Основне її завдання – надати користувачеві статичний HTML із необхідними даними. На відміну від CSR, SSR не вимагає додаткового виклику API до сервера, оскільки саме сервер генерує шаблон HTML і завантажує дані.
У більш сучасних рішеннях на зразок Next.js використовується гідратація, коли статичний HTML гідратується на клієнтській стороні за допомогою JS. Можна порівняти це із заварюванням швидкорозчинної кави: кавовий порошок – це HTML, а вода – це JS. При змішуванні порошку з водою ви, очевидно, отримаєте каву.
Але що таке Jamstack? Jamstack аналогічний SSR, оскільки клієнт отримує простий HTML. Але під час SSR клієнт отримує HTML з сервера, а у випадку з Jamstack програми передають заздалегідь згенерований HTML прямо з CDN. У зв’язку з цим вони зазвичай завантажуються швидше, але тут розробникам складніше створювати динамічний контент. Такі програми рахунок попередньої генерації HTML хороші клієнта. Однак при використанні великого обсягу JS-коду на стороні клієнта стає все складніше виправдати використання Jamstack замість СSR.
І SSR, і Jamstack мають особливості. Спільне з-поміж них те, що вони не навантажують клієнта рендерингом всієї сторінки, використовуючи JS.
Коли ви оптимізуєте SEO свого сайту, рекомендується використовувати SSR або Jamstack, оскільки порівняно з CSR ці техніки повертають HTML-файли, зручні для перегляду пошуковими роботами. Пошуковики, звичайно, також можуть переглядати та компілювати JS-файли для CSR. Хоча відображення кожного JS-файлу в додатку з CSR може бути витратним за часом і знижувати ефективність SEO вашого сайту.
SSR і Jamstack дуже популярні, і все більше проектів переходять на кадри для SSR на кшталт Next.js і Nuxt.js, відмовляючись від їх ванільних CSR-аналогів – React і Vue. Головна причина в тому, що SSR-фреймворки забезпечують більшу гнучкість щодо SEO. У Next.js є цілий розділ, орієнтований на SEO оптимізації.
Додаток з SSR зазвичай містить шаблонизатори, які впроваджують змінні HTML під час його передачі клієнту. Наприклад, у Next.js можна завантажити список студентів, написавши:
Jamstack популярний для сайтів документації, які зазвичай компілюють код HTML-файли і розміщують їх в CDN. Файли Jamstack зазвичай до компіляції в HTML використовують розмітку Markdown. Ось приклад:
---
author: Agustinus Theodorus
title: 'Title'
description: Description
---
Hello World
Активне кешування пам’яті
Коли вам потрібна можливість швидко отримувати дані, з якими ви вже працювали, зверніться до кешування. Ця техніка передбачає збереження нещодавно використаної інформації для швидкого завантаження. Реалізувати кешування можна двома шляхами – за допомогою супершвидкого сховища ключ-значення на зразок Redis для збереження ключів даних та значень або за допомогою простого кеша браузера, в якому дані зберігатимуться локально.
При кешуванні дані зберігаються лише певний час, так що як постійне сховище кеш не підходить. Ця техніка дуже придатна в продакшен-середовищі і стає актуальною в міру дорослішання програми.
Але як робити правильний вибір між кешем Redis (серверним) та кешем браузера (локальним)? Обидва ці варіанти можна використовувати одночасно, але кожен із них буде слугувати своїй меті.
Серверний кеш допомагає скоротити затримку між фронтендом та бекендом. Оскільки бази даних у форматі ключ-значення працюють швидше за традиційні реляційні БД SQL, це значно зменшує час відповіді API. При цьому локальний кеш дозволяє програмі зберігати стан після оновлення сторінки, що прискорює відображення при подальших поверненнях до неї.
Загалом, якщо ви хочете підвищити швидкодію програми, то можете використовувати для прискорення API серверний кеш. Якщо ж ви хочете зберігати стан програми, варто вдаватися до локального. І хоча локальний кеш може здатися марним, він допомагає скоротити кількість викликів API до бекенду, зберігаючи стан, який рідко змінюється. Однак локальний кеш працює ефективніше при поєднанні з «живими» даними.
Генерація подій даних
Встановити з’єднання в режимі реального часу між фронтендом та бекендом можна через WebSockets. WebSockets – це механізм двосторонньої комунікації, що спирається на події.
У стандартній архітектурі WebSocket фронтенд-додаток підключається до WebSocket API, шини подій або бази даних. У більшості архітектур WebSocket це використовується як альтернатива REST, особливо в додатках на зразок чатів, коли опитування бекенда кожні кілька секунд стає неефективним. Ця техніка дозволяє отримувати по двосторонньому каналу оновлення з іншого боку без створення нового запиту.
У порівнянні з HTTP-запитами WebSocket створює дуже компактне підключення, що перевіряється на активність. Поєднання WebSocket з локальним кешем браузера дозволяє створити програму, що працює в реальному часі. Стан цієї програми можна оновлювати на основі подій, що одержуються за WebSocket. Однак тут все ж таки є ряд каверз, пов’язаних з швидкодією, масштабованістю і потенційними конфліктами даних.
У чистій реалізації WebSocket, як і раніше, є безліч недоліків. Використання цієї технології замість стандартних HTTP-дзвінків повністю змінить поведінку програми. Навіть одна невелика проблема з підключенням зможе вплинути на весь досвід користувача. Наприклад, WebSocket неспроможна забезпечити швидкодію реального часу – коли потрібно зв’язатися з базою даних, використовується запит GET. Щоб зробити WebSocket раціональним та доцільним вибором у бекенді необхідно усунути ряд слабких місць, що перешкоджають ефективній роботі в режимі реального часу.
Для реалізації таких можливостей потрібний основний архітектурний шаблон, наприклад, «генерація подій» який можна використовувати для створення надійних real-time додатків. І хоча він не гарантує загальне підвищення швидкодії програми, цей шаблон явно покращить досвід користувача, надавши клієнтам можливість використовувати UI в режимі реального часу.
У сучасному JS доступні для використання провайдери WebSocket. Клас WebSocket відкриває з’єднання з віддаленим сервером і дозволяє прослуховувати, коли WebSocket створює з’єднання, закриває його, повертає помилку або повертає подію.
const ws = new WebSocket('ws://localhost');ws.addEventListener('message', (event) => {
console.log('Message from server ', event.data);
});
Бажаєте реагувати на події сервера? Додайте функцію addEventListener та вставте зворотний дзвінок, який вона використовуватиме.
ws.send('Hello World');
Бажаєте надсилати повідомлення? І тут WebSocket має рішення. Надсилання повідомлень із сервера можна реалізувати за допомогою функції send. Причому це не складніше реалізації Hello World. Приклади взято з документації MDN .
Попереднє та відкладене завантаження даних
Попереднє і відкладене завантаження вже стали звичайними прийомами серед розробників фронтенду. Ефективне використання клієнтських ресурсів та пропускної спроможності може значно покращити швидкодію програми.
Попереднє завантаження
Ця техніка дає розробникам детальніший контроль над вільною пропускною смугою клієнта, завантаженням ресурсів та сторінками, які клієнту можуть знадобитися наступними. Коли сайт має посилання для попереднього завантаження, браузер мовчки завантажує її вміст, зберігаючи його в кеші. Коли користувач згодом переходить за такими посиланнями, вони завантажуються значно швидше.
URL для попереднього завантаження встановлюються в атрибуті relHTML-елемента link. Однак дана техніка має як плюси, так і мінус.
Плюси:
Операція попереднього завантаження чекає, поки мережа браузера не виявиться вільною і зупиняється, як тільки ви запустите якийсь мережевий процес, натиснувши посилання або активувавши функцію відкладеного завантаження.
Попереднє завантаження кешує дані у браузері, прискорюючи переходи при перенаправленні за посиланням.
Мінус:
Цей прийом можна використовувати для завантаження трекерів, що ставить безпеку користувача під загрозу.
Відкладене завантаження
Відкладене завантаження – це стандартний шаблон завантаження даних, що дозволяє клієнту завантажувати результати на вимогу, а не всі разом. При використанні цього методу клієнт отримує частини сайту поступово у процесі прокручування його подання.
Відкладене завантаження прискорює роботу сайту за рахунок того, що браузер може сконцентруватися на важливіших для показу ресурсах. Вам не потрібно завантажувати всі зображення/текст сайту, якщо ви їх не бачите. Однак відкладене завантаження допомагає лише відкласти скачування ресурсів, не роблячи їх менше і не скорочуючи витрати на цю процедуру.
Якщо вас цікавить аналогічне рішення, але з ухилом у бік зниження обчислювальних витрат, рекомендую звернути увагу на принцип Resumability.
Resumability
Багато розробників про принцип Resumability ніколи не чули. При використанні цієї техніки JS-код частково малюється на сервері, після чого кінцевий стан малювання серіалізується і відправляється клієнту з відповідним корисним HTML-навантаженням. Потім клієнт завершує розпочату відмальовку, витрачаючи на це вже суттєво менше часу та ресурсів. По суті, таким чином ми використовуємо сервер для виконання всієї основної роботи, після чого за допомогою серіалізації передаємо клієнту лише малу частину JS-коду для виконання.
Головна ідея Resumability полягає у передачі стану програми від сервера клієнту у вигляді серіалізації. Замість завантаження всього коду (HTML, JS) з подальшим його гідратуванням у фронтенді при використанні Resumability ми розбиваємо парсингу JS-коду на стадії та відправляємо їх клієнту у вигляді HTML.
Завантаження сторінок буде блискавичним, оскільки клієнт замість перезавантаження чогось десеріалізуватиме стан, впроваджений в HTML. Resumability є досить чужорідною концепцією і багатьох проектів здасться зовсім незвичним прийомом. Придумав цей шаблон творець Qwik, Міско Хевері.
Qwik– це JS-фреймворк, що внутрішньо працює за принципом Resumability, який у нього закладався спочатку. Якщо ж говорити про такі фреймворки, як React і Vue, то вони ніколи не зможуть задіяти техніку Resumability, не пожертвувавши зворотною сумісністю. Причина в тому, що компонент відкладеного завантаження Qwik працює асинхронно на відміну від більшості синхронно влаштованих фреймворків JavaScript.
Завдання Qwik – завантажувати якнайменше JS-коду. Справа в тому, що робити це відкладено досить важко, а в деяких випадках навіть неможливо. Чим менше вам потрібно, тим краще. Resumability дозволяє розробникам детально налаштувати відкладене завантаження та скоротити споживання пам’яті мобільними програмами, оптимізуючи під них сайт.
Використання Qwik у певному сенсі нагадує React – зокрема вони схожий синтаксис. Ось фрагмент коду Qwik. Основа програми буде представлена у формі HTML:
Фрагмент вище показує, як серверна частина Qwik серіалізує основний компонент, використовуючи метод renderToString. Після цього клієнту потрібно лише спарсити чистий HTML і десеріалізувати стан JS без необхідності їх перезавантажувати.
Узагальнення
Швидкодія програми для клієнта дуже важлива. Чим більше ресурсів вам доводиться завантажувати, тим більше часу знадобиться програмі під час запуску. При цьому до процесу очікування завершення завантаження користувачі стають менш терпимими. Так що чим менше часу вантажиться ваш сайт, тим краще.
Однак, якщо ви працюєте над великими корпоративними програмами, то тут спосіб оптимізації вже знайти складніше. Шаблони завантаження даних є одним з можливих варіантів підвищення швидкодії ваших додатків. У цій статті ми розібрали їх п’ять:
Відображення на стороні сервера (SSR) та Jamstack.
Активне кешування пам’яті.
Генерація подій даних.
Попереднє та відкладене завантаження.
Resumability.
Кожен із них ефективний на своєму місці.
SSR та Jamstack зазвичай добре підходять для додатків, що вимагають меншого керування станом на стороні клієнта. З появою сучасних фреймворків на зразок React все більше людей познайомилися з патерном відмальовки на клієнтській стороні (CSR), але в результаті спільнота все ж таки повертається до SSR. Техніка SSR використовується у старих MVC фреймворках, де за допомогою шаблонізаторів на основі даних бекенда генерується HTML. Jamstack – це ще більш стара ілюстрація початкового веб-середовища, в якому використовувався лише HTML.
Активне кешування пам’яті дозволяє швидше завантажувати дані з API. Ця техніка вирішує важливу проблему завантаження даних шляхом їх кешування або на віддаленому сервері (Redis) або локально в браузері. Крім цього, вона використовується в шаблоні попереднього завантаження даних.
Що стосується генерації подій, цей архітектурний шаблон доповнює засновані на подіях WebSocket API, що працюють в реальному часі. Простих старих WebSocket недостатньо для повноцінної ефективності, оскільки хоч сам WebSocket і працює в реальному часі, регулярні виклики API до бази даних створюють вузьке місце. Шаблон генерації подій усуває цю проблему, створюючи для завантаження даних окрему базу даних.
Попереднє та відкладене завантаження представляють найпростіші в реалізації рішення. Мета першого – тихо завантажувати дані, коли мережа перебуває у вільному стані. При цьому клієнти зберігають завантажені посилання в кеші браузерів, використовуючи їх у готовому вигляді при безпосередньому зверненні.
Відкладене завантаження скорочує обсяг ресурсів, необхідних для завантаження при першому натисканні. Вам потрібні лише ті, які ви бачите безпосередньо після завантаження сторінки. І цю техніку додатково розширює шаблон Resumability. Він має на увазі відкладене завантаження JS-компонентів шляхом їх часткового відтворення на сервері з подальшою серіалізацією стану для завершення розпочатого відтворення вже на стороні клієнта за допомогою HTML.
Подальші кроки
Вироблення навичок оптимізації додатків є безперервним процесом. Вам потрібно продумувати все наперед у проектах, які реалізуєте день у день. Шаблони завантаження даних – це лише один із способів для підвищення швидкодії.
Однак, перш ніж втручатися в процес структуризації та споживання даних додатком, краще спершу ознайомитися з усіма можливими підводними каменями.
Криптовалюти – це віртуальні активи, функціонування яких забезпечується мережею децентралізованих комп’ютерних нод (вузлів). Більшість із них побудовано на основі блокчейну — бази даних про транзакції в ланцюжку зв’язаних блоків.
Криптовалюти переважно використовуються для розрахунків між користувачами мережі, оплати комісій за перекази, а також для зберігання капіталу. Однак вони можуть мати безліч інших функцій та обмежень. У деяких блокчейнах можна випускати необмежену кількість криптовалют.
Залежно від функцій та сфери застосування розрізняють різні типи криптовалют, у тому числі стейблкоіни, NFT , токени управління та обернені активи.
Блокчейн дозволяє безпосередньо та без обмежень взаємодіяти з криптовалютами. Децентралізація та відсутність контролю будь-якої країни чи організації усуває можливість блокування коштів та інші ризики.
Коли з’явилися криптовалюти
Пропозиції щодо створення криптовалюти висловлювали ще до появи інтернету. Перші алгоритми, створені задля передачу цінності через інтернет, запропонував американський криптограф Девід Чаум. Наприкінці 80-х років він заснував відповідний проект під назвою DigiCash. Однак той закінчився невдачею.
Одним із проектів, близьким до сучасних криптовалютів, є b-money . Проект започаткував програміст Вей Дай. У b-money він уперше запропонував механізм консенсусу Proof-of-Work (PoW) для фіналізації транзакцій та розподілену базу даних для зберігання інформації про транзакції.
Біткоїн, створений анонімним користувачем під ніком Сатоші Накамото, став першою успішною криптовалютою, яка набула широкого поширення. Алгоритм роботи однойменного блокчейна багато в чому базується на ідеях Вей Дая і, у ширшому значенні, руху шифропанків.
Наступним кроком у розвитку віртуальних активів стала платформа смарт-контрактів Ethereum, яку заснував Віталік Бутерін. Запуск основної мережі відбувся у 2015 році. Завдяки смарт-контрактам блокчейн Ethereum надав можливість випускати необмежену кількість криптоактивів та програмувати їх функції.
Криптовалюти та блокчейн: відмінності від традиційних фінансів та грошей
Надійність блокчейну та закладені в ньому механізми захисту даних зробили криптовалюти гідною альтернативою традиційній грошовій системі. Перекази цифрових активів можна здійснювати безпосередньо між користувачами, а за їх перевірку та підтвердження відповідає протокол мережі, наданий безліччю незалежних вузлів. Після надсилання та верифікації транзакції її неможливо скасувати.
Інформація про переклади зберігається у відкритій базі даних. Ключовою технологією, що дозволяє взаємодіяти з віртуальними активами, є блокчейн. Криптографічні методи, що використовуються в ньому, виключають можливість зміни даних про виконані транзакції.
Завдяки децентралізації у блокчейні вдалося вирішити проблему єдиної точки відмови у базах даних та платіжних системах, забезпечивши універсальний захист від цензури. Віртуальні активи в публічних блокчейнах не схильні до впливу контролюючих органів та зовнішніх маніпуляцій. У третьої сторони немає можливості заблокувати кошти або скасувати транзакцію.
Криптовалюти можуть не бути під контролем будь-якої однієї організації, що дозволяє використовувати їх у будь-якій юрисдикції. Біткоїн – найбільш відомий приклад такого активу. Нові віртуальні активи випускають у процесі роботи блокчейну. В алгоритмі роботи конкретного цифрового активу закладено такі параметри як загальна емісія та швидкість випуску нових монет.
Користувач може створити необмежену кількість адрес. Останні зазвичай не дозволяють отримати інформацію про нього. Тільки спеціалізовані інструменти блокчейн-аналізу дають змогу відстежити рух коштів та визначити джерела їх надходження.
Як працює криптовалюта : ключові особливості
Блокчейн
Більшість криптовалют використовують технологію під назвою блокчейн. Останній є послідовністю ієрархічно пов’язаних блоків. Він містить базу даних про всі проведені транзакції. Нові транзакції записуються в блоки, які створюють оператори нод. Кожен із комп’ютерних вузлів зберігає свою копію блокчейна і під час досягнення консенсусу підтверджує нові блоки, передаючи результат іншим нодам. За підсумками цієї інформації змінюються баланси користувачів.
Хешування
У криптовалютах широко застосовуються хеш-функції. Остання дозволяє “згорнути” довільний масив даних в один рядок – хеш. Блокчейн є єдиним цілим, оскільки кожен наступний блок включає хеш попереднього. Використання інших даних призводить до суттєвої зміни цього рядка. Алгоритм унеможливлює скасування транзакції без зміни всіх наступних блоків.
Алгоритм консенсусу
За підтвердження транзакцій та перевірку всіх даних блокчейна відповідає алгоритм консенсусу, в якому беруть участь члени мережі – ноди. Найбільш популярними алгоритмами консенсусу є вже згаданий Proof-of-Work (використовується в біткоїні) та Proof-of-Stake .
Щоб підтвердити транзакції, вузли витрачають обчислювальну потужність або блокують власні кошти, які є гарантією достовірності даних. Після додавання нового блоку неможливо повторно витратити кошти, витрачені на поточному етапі. У процесі досягнення алгоритму його учасники отримують нові криптовалюти (як у PoW , так і в PoS ). Таким чином, ці механізми є способом емісії нової криптовалюти.
Адреси
Блокчейн-адреси, де зберігаються криптовалюти, побудовані з урахуванням двох ключів — громадського і приватного. Перший використовується для «відкритої» частини адреси, другий — для підпису транзакцій та доступу до адреси. Закритий ключ призначено лише для власника адреси. Існуючі комп’ютерні потужності не дозволяють зламати блокчейн-адресу, зокрема «відгадати» приватний ключ методом підбору. Створювати блокчейн-адреси та керувати ними можна у спеціальному додатку – гаманць .
Транзакції
Щоб перекласти криптовалюту, користувач надсилає до мережі «доручення», що містить інформацію про суму переказу та адресата. Дані перекладу автоматично верифікуються електронним підписом за допомогою приватного ключа. Після потрапляння повідомлення до мережі воно включається до одного з наступних блоків, який «добувають» ноди блокчейна. Будь-яка нода може перевірити підпис кожного перекладу, використовуючи публічний ключ. Такий алгоритм гарантує збереження коштів та неможливість здійснення транзакцій третіми особами.
Незмінність даних
Після додавання блоку в ланцюжок усі його транзакції вважаються підтвердженими та незворотними. Верифікація всіх транзакцій, зокрема минулих, відбувається кожен цикл досягнення консенсусу мережі. Недостовірні дані можуть потрапити в блокчейн, тільки якщо зловмисник зможе розшифровувати хеш блоків або контролюватиме суттєву частку всіх нод мережі. Наприклад, у разі біткоїну цей поріг становить 51%. За даними на 13 жовтня 2022 року, у всьому світі працює понад 15 000 нод , що робить атаку на біткоїн практично неможливою.
Класифікація криптовалют: монети та токени
Для створення та здійснення операцій з криптовалютою необхідний блокчейн, який потребує наявності інфраструктури та економічних стимулів.
Головний віртуальний криптоактив, який забезпечує функціонування ланцюжка блоків, називається нативним. Останній застосовується для оплати трансакційних комісій та виплат винагород вузлам. На платформах, які дозволяють запускати смарт-контракти, криптовалюта нативна використовується для оплати їх виконання. У біткоїну та Ethereum нативна монета носить ту саму назву, що і проект, і торгується під тикерами BTC та ETH, відповідно.
Різні криптоактиви можуть з’явитися в результаті хардфорку. До них відносяться, наприклад, Bitcoin Cash та Ethereum Classic.
Сьогодні криптовалюте вже не обов’язково потрібен окремий блокчейн: багато криптоактивів створюють для використання в різних додатках, що працюють в одній мережі. Такі криптовалюти називають токенами. Портал CryptoSlate відслідковує котирування близько 1300 токенів, випущених у мережі Ethereum.
Випуск токенів став можливим завдяки смарт-контрактам, які стали популярними після запуску Ethereum. Створити власну криптовалюту може будь-який користувач, який має навички програмування. Найбільш відомим стандартом токенів є ERC-20.
Які бувають токени
Віртуальні активи, які використовуються для розрахунків та інших цілей у проектах та децентралізованих додатках називаються ютіліті-токенами.
Найчастіше токени застосовуються для управління проектом. Спільнота власників активу може приймати рішення щодо подальших напрямів розвитку проекту. Власники мають можливість виставляти пропозиції на голосування та брати участь у опитуваннях. Вага голосу при цьому пропорційна числу монет.
Монети можуть надавати певні права чи привілеї. Токени використовують для залучення коштів при первинній пропозиції монет (ICO). У деяких проектах віртуальні активи надають право на частину прибутку проекту. Токени, що мають набір функцій у рамках програми або мережі, також називають ютіліті-токен (utility tokens).
Криптовалюти, офіційно визнані цінними паперами, називають сек’юріті-токенами. На жовтень 2022 року є принаймні кілька десятків таких криптоактивів.
На базі блокчейнів реалізовані стейблкоіни. Вартість цих токенів прив’язана до ціни певного активу, наприклад, долара США. Найчастіше вони застосовуються для розрахунків та накопичення заощаджень. Їхні емітенти зберігають у резервах відповідну кількість валюти, що гарантує стабільність ціни та збереження коштів.
Платформи смарт-контрактів дозволяють випускати обгорнуті токени. Останні прив’язані за вартістю криптовалюти з іншого блокчейна. Наприклад, для того щоб використовувати біткоїн у мережі Ethereum випущений токен WBTC. Прив’язка реалізується завдяки тому, що випуск токена вимагає блокування відповідного обсягу криптовалюти, що виступає в якості забезпечення. Для розблокування віртуальних активів обгорнуті токени спалюються.
У сучасних мережах випускаються невзаємозамінні токени (NFT). Це унікальні монети, які представляють певні цифрові об’єкти (зображення, аудіо та відеофайли). NFT стали об’єктами колекціонування. Перші незамінні токени є раритетами і мають високу вартість (наприклад, CryptoPunks). Також NFT можуть виконувати інші функції, наприклад використовуватися як аватари або квитки на певні заходи.
Існують криптовалюти, які є похідними фінансовими інструментами. На основі таких токенів, зокрема, збудовано ліквідний стейкінг. На відміну від стейблкоїнів, їх ціна регулюється ринковими механізмами. Деякі торгові платформи випускають токени з кредитним плечем.
Як формується цінність криптовалюти
При створенні блокчейну розробники ухвалюють рішення про те, якою буде токеноміка проекту. Остання визначає алгоритм випуску та розподіл монет між користувачами. Емісія – це кількість монет, що перебуває в обігу. У деяких проектах початковий випуск дорівнює нулю, наприклад, у біткоїні. У таких випадках криптовалюта може випускатися постійно або періодично. Ряд проектів мають постійну емісію.
Розподіл початкового випуску монет між користувачами визначається розробником. Зазвичай частина активів залишається командою проекту. Кошти резервуються на рекламу розробку та розвиток проекту. Частина монет використовується для залучення інвестицій. Їх можуть купити великі інвестори в рамках одного або кількох раундів. Багато проектів використовують публічний токенсейл для продажу віртуальних активів усім охочим. В інших випадках практикують розподіл монет між активними користувачами – аірдроп.
Алгоритми роботи криптовалют можуть вимагати блокування частини монет (наприклад, при стейкінгу). Оскільки частина активів внесена до смарт-контрактів, певний обсяг коштів недоступний. Як правило, випуск криптовалюти обмежений максимальною емісією. Для проектів, які постійно генерують монети, загальна їхня кількість ніколи не перевищить цю величину. Наприклад, максимальна пропозиція BTC становить 21 млн.
На вартість криптовалюти впливає халвінг. Механізм використовується у криптовалютах, які виплачують фіксовану винагороду за блок. Халвінг відбувається періодично та призводить до зниження цієї суми. Подія зменшує інфляцію, а за наявності попиту актив стимулює зростання його вартості.
На ціну криптовалюти впливає спалювання монет. Останнє передбачає виведення з обігу певного обсягу активів. Щоб знищити монети, власники надсилають їх на спеціальні адреси чи смарт-контракти. При цьому можливе стрибкоподібне зростання вартості криптовалюти, а періодичні спалювання підвищують її дефіцитність.
Криптовалюти, на відміну від фіатних грошей, не контролюються певною організацією або державою. Тому для віртуальних активів характерна висока волатильність. Їхня вартість визначається переважно ринковими механізмами. Цінність криптовалюти залежить від співвідношення між попитом та пропозицією. Якщо на ринку продається значний обсяг монет, а охочих купити мало, відбувається падіння вартості. Коли попит перевищує пропозицію, ціна зростає.
Основним показником затребуваності віртуального активу є ринкова капіталізація. Остання дорівнює добутку обсягу монет, що у зверненні вартість одиниці.
30 листопада лабораторія штучного інтелекту OpenAI представила свій чат-бот ChatGPT, що базується на нейромережевій мовній моделі GPT-3.5. Про розробку майже відразу почали писати як про саму «людську», «навчену» та «достовірну». Оптимісти передбачають, що ChatGPT замінить людину в написанні текстів та коду, песимісти жахаються, що вона замінить людину в написанні текстів та коду. І багато хто бачать у розвитку моделі ChatGPT пряму загрозу Google.
Хто такий ChatGPT?
Чат-бот, який не навчився (і не навчиться?) поганому. ChatGPT, це високорозвинений та вихований ІІ: він здатний давати вичерпні відповіді, сперечатися та відхиляти недоречні питання.
Розробники створювали ChatGPT на суперкомп’ютері Azure AI на основі мовної моделі GPT-3,5 компанії OpenAI. Чат-бот прагнули зробити простим у використанні, коректним та «людяним». Його навчали за допомогою великої кількості текстів з Інтернету та системи Reinforcement Learning from Human Feedback.
Bloomberg розвиває тему можливостей: на запит ChatGPT може видавати базовий програмний код, елементарний фінансовий аналіз, забавні вірші та пісні, імітації художнього тексту, реферати практично на будь-яку тему, резюме технічних статей або наукових концепцій, прогнози, персональні поради та відповіді практично на будь-яке питання .
Варто відразу обмовитися, що при всьому прагненні бути коректним, він не застрахований від неправильних відповідей. Оглядач Bloomberg у відповідь на запит біографії Муссоліні отримав історію його захоплення скейтбордами. Журналісти Wired були збентежені порадами «як подрібнений порцеляна, додана в грудне молоко, може підтримувати травну систему немовлят» і зазначили, що чат-бот часто мислить стереотипами, яким схильне все суспільство. Stack Overflow взагалі заборонив публікувати відповіді, згенеровані ІІ, саме через те, що вони часто створювали лише ілюзію правильних рішень.
Ілон Маск та колишній президент Y Combinator Сем Альтман заснували OpenAI у 2015 році. У 2016 році компанія запустила Gym, набір інструментів для створення систем самонавчання ІІ. У тому ж році з’явилася платформа Universe.
У 2018 році, через три роки після заснування OpenAI, Маск залишив раду директорів компанії. Згідно з офіційною версією, гендиректор Tesla подав у відставку, щоб «усунути потенційний майбутній конфлікт», який міг виникнути через те, що автовиробник також зосередив свою увагу на ІІ. Пізніше Маск сказав, що пішов із компанії через незгоду з поглядами команди OpenAI на майбутній розвиток: він вважав, що некомерційний характер компанії має зробити її більш відкритою.
2019 року компанія створила чат-бот, який міг писати достовірні фейкові новини. Спочатку в OpenAI заявили, що бот настільки досяг успіху в цьому занятті, що вони вирішили не випускати його в люди. Але пізніше компанія таки анонсувала версію інструменту ІІ під назвою GPT-2. 2020 року з’явився GPT-3.
Про своє партнерство з Microsoft OpenAI оголосила наприкінці 2019 року. Незадовго до того компанія відмовилася від некомерційного статусу. Інвестиції Microsoft становили $1 млрд, і вона разом із OpenAI ставала володаркою ексклюзивної ліцензії на всі розробки.
Торік з’явилося ще одне дітище – Dall-E – ІІ для створення зображень.
Після виходу ChatGPT Ілон Маск назвав його «жахливо добрим», впевнений, що «ми недалеко від небезпечно сильного ІІ».
Через п’ять днів після запуску у чат-бота було більше мільйона користувачів, і їхня кількість збільшується.
Що OpenAI збирається робити далі
У планах OpenAI зробити ChatGPT доступним у вигляді інтерфейсу прикладного програмування, щоб сторонні розробники інтегрували його у свої сайти або додатки без необхідності розбиратися в базовій технології.
Це означає, що якщо все піде, як заплановано, невдовзі компанії зможуть використовувати ChatGPT для створення віртуальних помічників, ботів для обслуговування клієнтів або маркетингових інструментів. Писати романи, п’єси, публіцистичні статті – поки що немає. Але ChatGPT міг би взяти на себе перегляд документів та інші важкі завдання. Він непоганий помічник, коли треба вигадувати нові незвичайні ідеї чи спрощувати процес ухвалення рішень. І, до речі, він сам міг би генерувати ідеї свого використання, бо фантазії експертів поки що виглядають скромними.
Він нас погубить: погляд скептиків
Є побоювання, що ChatGPT поставить під удар систему освіти. Якщо ІІ непогано виглядає як помічник у процесах навчання, то на етапі контролю та оцінки результатів він може нашкодити: ніколи ще студентські реферати не виглядали такими унікальними та «рукотворними». Techcrunch цитує Пола Кедроскі з Массачусетського технологічного: “Ганьба OpenAI за запуск цієї кишенькової ядерної бомби без обмежень у непідготовлене суспільство”.
Він упевнений, що це той випадок, коли технології можуть проковтнути творців. «Хтось може сказати: «Те саме відбувалося, коли на автомобільні заводи прийшла автоматизація і робітники залишилися без роботи?». Але це зовсім інше. Ці специфічні технології навчання самокаталізують; вони навчаються на запитах. Таким чином, роботи на виробничому підприємстві, хоч і руйнували і створювали неймовірні економічні наслідки для людей, які там працюють, не розгорнулися і не почали поглинати все, що відбувається всередині заводу, переміщаючись по секторах. Хоча це те, що ви повинні очікувати (ІІ).»
The Verge бачить причини бути обережними з ChatGPT у «надлишку можливостей»: моделі ІІ – це «чорні ящики», вони настільки величезні та складні, що ми не до кінця розуміємо, як вони працюють, не робимо всіх висновків і не прораховуємо всіх варіантів розвитку та всіх майбутніх наслідків.
ChatGPT – це ” стохастичний папуга “, позбавлений людиноподібного розуміння світу як складної та абстрактної системи і лише повторює вже існуючі словесні формули.
Загроза Google
Те, в якому вигляді ChatGPT видає відповіді на питання, має напружити Корпорацію добра. Оглядач Techcrunch упевнений, що розробка OpenAI підібралася найближче до того, як має працювати пошукач.
Цю ж ідею розвиває Bloomberg . Робота Google побудована так, що він переглядає мільярди веб-сторінок, індексує цей контент, а потім ранжує його як найбільш релевантні відповіді. На виході ми отримуємо список посилань. ChatGPT пропонує дещо більш привабливе для змучених свободою вибору інтернет-користувачів: єдина відповідь, заснована на власному пошуку та синтезі цієї інформації.
Але Google навряд чи піде шляхом генерації власних унікальних відповідей на питання, тому що це зламає його бізнес-модель: згідно з даними, зібраними тим самим Bloomberg, близько 81% виручки Alphabet Inc. у розмірі $257,6 млрд у 2021 році припадало на рекламу, більша частина якої була з оплатою за клік.
З одного боку, нехай розквітають усі квіти, але сам автор публікації визнається, що в 13 із 18 пошукових запитів ChatGPT виявився суб’єктивно кращим і кориснішим, ніж Google. При цьому Microsoft має свій пошуковик, Bing, і вона точно не пропустить привабливої можливості інтегрувати в нього ІІ.
Трохи прикладної культурології
Усі дискусії, що розгортаються навколо ChatGPT, за великим рахунком виявляють культурний код, реалізований неодноразово в багатьох літературних творах — від Пігмаліона до Франкенштейна: неминучий суперечка творця та його «творіння», що загрожує перетворитися на бій.
Yahoo розглянув схожий сюжет в історії з ChatGPT, коли технології будуть здатні замінити людину, і він може не знайти собі місця у майбутньому.
Автоматичний маркет-мейкер (Automated Market Maker, AMM) – програмний алгоритм контролю ліквідності та ціноутворення криптоактивів на децентралізованих біржах.
AMM-системи широко застосовуються у сфері DeFi, зокрема на децентралізованих біржах (DEX), таких як включаючи Uniswap, Balancer, Bancor та Curve.
Для створення децентралізованих ринків AMM використовує ліквідність у криптовалютних загальнодоступних пулах із кількох токенів, заблокованих у спеціальних смарт-контрактах.
Як з’явився автоматичний маркет-мейкер (АММ)?
Автоматичний маркет-мейкер (AMM) – автономний торговельний механізм, на якому працює більшість торгових DeFi-протоколів . Він забезпечує рух капіталу та виконання обмінних операцій користувачів на доступних ринках криптоактивів.
Першим відомим розробником, хто заговорив про реалізацію AMM, був член команди проекту Gnosis Алан Лю. Його ідеї були викладені засновником Ethereum Віталіком Бутеріним на Reddit у 2016 році та в особистому блозі у липні 2017 року.
Ця концепція стала основою протоколу платформи Uniswap, яка отримала перший грант у розмірі $100 000 від Ethereum Foundation. Окрім того, Віталік Бутерін консультував розробників Uniswap.
Згодом АММ став широко відомим саме завдяки Uniswap. Водночас однією з перших успішних реалізацій AMM можна назвати платформу Bancor Network, яка зібрала $140 млн через ICO у червні 2017 року.
Як пули ліквідності пов’язані з АММ?
Ключовим елементом, необхідним роботи АММ, є пул ліквідності — своєрідне сховище криптоактивів як смарт-контракта . Пул ліквідності зазвичай складається з двох криптоактивів і формує ринок — аналог торгової пари на централізованій біржі.
Одні учасники пулу блокують свої кошти на отримання доходу з допомогою комісій за обмін. Таких користувачів називають постачальниками ліквідності.
Інша категорія — безпосередні користувачі децентралізованої біржі, які обмінюють криптовалюти в протоколі (такі операції називаються «свопи»), використовуючи якийсь із пулів.
Щоб краще зрозуміти пули ліквідності, розглянемо, що призвело до їхнього створення.
Перші DEX-біржі працювали на Ethereum та використовували для торгівлі стандартну книгу ордерів, що застосовуються на централізованих біржах. Щоб такий торговельний механізм був ефективним, він повинен мати дуже високу швидкість обробки транзакцій. Враховуючи, що операції на децентралізованій біржі підтверджуються через блокчейн, реальна швидкість та можливості таких DEX були вкрай обмежені. АММ дозволила знайти вирішення цієї проблеми.
Таким чином, AMM — принципово інший спосіб створення ринку активів, будучи формулою або правилами, за якими протокол працює із заявками на купівлю або продаж, а також із резервами користувачів.
Як працюють пули ліквідності?
У пулах можна використовувати два і більше активів. Наприклад, на біржі Uniswap можна створювати пули для парних токенів. Платформа Balancer дозволяє створювати пули для трьох та більше токенів. А протокол Curve призначений для пулів на основі активів з аналогічною вартістю, таких як ETH та обернутий токен WETH або USDC та DAI . Роботу цих пулів регулює АММ.
Кожна з таких AMM-DEX може використовувати власні формули та правила для взаємодії з пулами ліквідності. Наприклад, протокол Uniswap використовує таку формулу: x * y = k.
У рівнянні x та y представляють кількість токенів, доступних у пулі ліквідності; k – Постійна величина, звана інваріантом. У випадку з Curve використовуються формули x * y = k та x + y = k.
За формулою x * y = k також працюють проекти SushiSwap та PancakeSwap – це найпоширеніший вид AMM-DEX.
Як відбувається ціноутворення активу у пулі ліквідності?
При блокуванні ліквідності в пулі її постачальник отримує спеціальні LP-токени, що підтверджують їхню частку в пулі. Їх можна як боргову розписку, володіння якої дає право отримувати комісії від обмінних операцій на біржі і повернути свою частку з пулу.
LP-токени – це переданий криптоактив, який можна продати або обміняти на відкритому ринку, а також інвестувати в сторонні програми DeFi.
Процес обміну одного активу в інший у вигляді пулу ліквідності називається свопом (swap). Суть процесу полягає в додаванні в пул тільки одного активу замість двох, як у випадку з LP. За проведення свопу пул стягує невелику комісію, яку можна порівняти з комісією за угоду на централізованій біржі, тобто 0,1-0,3%. Комісії розподіляються між постачальниками ліквідності пропорційно їх частці в пулі.
Приклад
Створимо умовний пул ліквідності для пари ETH/USDC. За ціною 1 ETH, яка дорівнює 2000 USDC, потрібно буде одночасно заблокувати в смарт-контракті будь-яку кількість цих двох монет у співвідношенні 1:2000. За такої ціни в пулі може бути 100 ETH та 200 000 USDC.
Баланс активів у пулі визначається їхньою ціною. Коли користувач вирішить обміняти 10 ETH, використовуючи вищеописаний пул, він внесе свої монети до смарт-контракту звичайною транзакцією. В обмін на свої 10 ETH він отримає 20000 USDC (без урахування комісії за обмін).
Після цього обміну баланс пулу складе вже 110 ETH та 180 000 USDC. Отже, вартість ETH у цьому пулі складе близько 1636 USDC замість 2000 USDC інших ринках. Така ситуація залучає арбітражних трейдерів, які отримують вигоду з дисбалансу шляхом додавання USDC до пулу, поки ціна не досягне ринкових 2 000 USDC за 1 ETH.
У чому недоліки АММ?
Хоча АММ став проривом для трейдингу та DeFi, він має ряд явних недоліків. По-перше, при здійсненні свопів за допомогою АММ існує високий ризик прослизання ціни. У свою чергу, це призводить до ризиків непостійних збитків для LP і майнером цінності (MEV) для звичайних користувачів.
Для захисту від подібних ризиків створюються й інші види AMM, такі як проект CowSwap , що поєднує розробки AMM-Balancer і протоколу Gnosis.
По-друге, на відміну централізованих бірж під час торгівлі через АММ можна розміщувати лише одне вид заявок. Торгувати лімітними заявками чи іншими видами, наприклад, Stop Loss, не можна.
Що таке непостійні збитки (Impermanent Loss)?
Непостійні збитки (Impermanent Loss, IL) – це тимчасові або нереалізовані збитки при утриманні активів у пулі ліквідності під час використання AMM-DEX. IL відносяться до постачальників ліквідності (LP), означаючи різницю в ціні на момент блокування токенів у пулі та фактичною ціною на момент утримання. Збитки називаються нереалізованими тому, що не фіксуються доти, доки ліквідність не виведена з пулу.
Як приклад візьмемо пул ліквідності на біржі Uniswap, що працює за класичною формулою x * y = k:
Постачальник ліквідності заблокував 1 ETH та 2000 DAI. Його частка у пулі становила 10%.
Всього в пулі знаходиться 10 ETH та 20 000 DAI – еквівалент 40 000 DAI.
Баланс пулу не змінювався, оскільки не було нових постачальників ліквідності.
Допустимо, що ринкова ціна ETH змінилася до 4000 DAI.
Тоді арбітражні трейдери скористалися ситуацією та змінили співвідношення в пулі на 5 ETH з одного боку та на 20 000 DAI з іншого. При цьому загальний розмір пулу залишився початковим – 40 000 DAI.
У цей момент постачальник ліквідності вирішив вивести свою частку з пулу – вона становить 10%.
З урахуванням поточного балансу пулу він виводить 0,5 ETH та 2000 DAI, хоча спочатку додавав 1 ETH та 2000 DAI.
Початкова вартість його частки була 4000 DAI (1 ETH плюс 2000 DAI) у перерахунку на стейблкоіни. Вартість активів на момент виведення склала ті ж 4000 DAI (0,5 ETH плюс 2000 DAI)
Однак, якби користувач просто утримував свої 1 ETH та 2000 DAI, то вартість його активів склала б вже 6000 DAI. У цьому полягає нереалізований збиток чи прибуток під час використання AMM-DEX.
Користувач також отримає 10% (пропорційно його частці в пулі) від усіх комісій пулу як нагороду за надання ліквідності. Нагорода може бути зменшена, наприклад, через податки, що відраховуються на адресу розробників або в казначейство проекту на майбутній розвиток.
Це умовний приклад різкого підвищення ціни одного активу на 50%, без урахування безлічі угод арбітражних трейдерів та часу, які необхідні для вирівнювання ціни
активу всередині пулу з ціною на централізованих біржах, де зміни відбуваються моментально.
При «спокійній» течії ринку до розрахунку непостійних збитків додають змінні рухи, як описав у своєму блозі розробник StarkNet Петериса Ерінса. У результаті прогнозних обчислень значення Impermanent Loss на дворазовому русі ціни активу становитиме близько 5,7%. Але це лише прогнозна величина — потенційні збитки передбачити дуже складно.
Як знизити ризики торгівлі за допомогою AMM?
Перш ніж використовувати пул ліквідності, слід прорахувати всі можливі комісії, які вам доведеться заплатити на момент введення та планованого виведення активів.
Необхідно враховувати можливість руху ціни активів на обидві сторони. Деякі потенційні проблеми, такі як ризик незмінних збитків (IL), можна розрахувати заздалегідь.
Для розрахунку показника ІЛ потрібно розуміти природу його походження. Також можна скористатися одним із калькуляторів непостійних збитків, доступних в Інтернеті.
React + TypeScript: необхідний мінімум
Чимало React-розробників запитують себе: чи треба мені вчити TypeScript? Ще як треба!
Переваги вивчення TS можуть бути зведені до наступного:
ваші шанси отримати більш високооплачувану роботу збільшаться;
у вашому коді буде набагато менше багів, його буде легше читати та підтримувати;
рефакторити код та оновлювати залежності стане набагато простіше.
Ця стаття являє собою мінімальне введення з використання TypeScript у React.
Основи TypeScript, необхідні React
Примітиви
Існує 3 основні примітиви, які є фундаментом для інших типів:
string // наприклад, "Pat"
boolean // наприклад, true
number // наприклад, 23 чи 1.99
Масиви
Тип масиву складається з примітивів чи інших типів:
number[] // наприклад, [1, 2, 3]
string[] // наприклад, ["Lisa", "Pat"]
User[] // кастомний тип, наприклад, [{ name: "Pat" }, { name: "Lisa" }]
Нарешті ми можемо винести параметри в окремий тип. Спойлер: така техніка часто використовується для проповнення компонентів React:
type User = {
firstName: string;
age: number;
role: UserRole;
}
functionfireUser({ firstName, age, role }: User) {
// ...
}
Типізація значення, що повертається функцією
Пет вважає, що просто звільнити працівника недостатньо. Тому може бути гарною ідеєю повертати користувача з функції.
Для визначення типу значення, що повертається функцією, також є кілька способів. Ми можемо додати : Typeпісля закривання дужки списку параметрів функції:
functionfireUser(firstName: string, age: number, role: UserRole): User{
// ...return { firstName, age, role };
}
// чи такconst fireUser = (firstName: string, age: number, role: UserRole): User => {
// ...return { firstName, age, role };
}
Якщо, наприклад, ми спробуємо повернути null отримаємо помилку:
Насправді, найчастіше ми не маємо необхідності визначати тип значення, що повертається функцією, явно. TypeScript відмінно справляється з припущенням (висновком) таких типів:
За наявності сумнівів у коректності TypeScript типу, що виводиться, достатньо навести курсор на назву змінної або функції (спасибі сучасним редакторам коду).
Інші речі, з якими вам доведеться мати справу
Існує ще кілька корисних речей, які можуть знадобитися при використанні TypeScript у React. Мабуть, найважливішими з них є:
Типом, що повертається компонентом є JSX.Element, як видно на наведеному нижче зображенні:
Якщо ми спробуємо повернути з компонента не JSX, то отримаємо попередження:
В даному випадку об’єкт user не є валідним JSX:
'UserProfile' cannot be used as a JSX component.
Its return type 'User' is not a valid JSX element.
Props
Як зазначалося раніше, props — це лише об’єкти:
enum UserRole {
CEO = "ceo",
CTO = "cto",
SUBORDINATE = "inferior-person",
}
type UserProfileProps = {
firstName: string;
role: UserRole;
}
functionUserProfile({ firstName, role }: UserProfileProps) {
if (role === UserRole.CTO) {
return<div>Hey Pat, you're AWESOME!!</div>
}
return<div>Hi {firstName}, you suck!</div>
}
// чи такconst UserProfile = ({ firstName, role }: UserProfileProps) => {
if (role === UserRole.CTO) {
return<div>Hey Pat, you're AWESOME!!</div>
}
return<div>Hi {firstName}, you suck!</div>
}
Зверніть увагу : при роботі над React-проектами ви, швидше за все, зустрінете багато коду, в якому використовується тип React.FC або React.FunctionComponent:
const UserProfile: React.FC<UserProfileProps>({ firstName, role }) {
// ...
}
Як пропов компонентам часто передаються функції зворотного виклику (коллбеки):
type UserProfileProps = {
id: string;
firstName: string;
role: UserRole;
fireUser: (id: string) =>void;
};
functionUserProfile({ id, firstName, role, fireUser }: UserProfileProps) {
if (role === UserRole.CTO) {
return<div>Hey Pat, you're AWESOME!!</div>;
}
return (
<><div>Hi {firstName}, you suck!</div><buttononClick={() => fireUser(id)}>Fire this loser!</button></>
);
}
voidозначає, що функція нічого не повертає.
Дефолтні props
Як ви пам’ятаєте, ми можемо зробити поле опціональним за допомогою ?. Те саме можна робити з props:
type UserProfileProps = {
age: number;
role?: UserRole;
}
Опціональний props може мати значення за замовчуванням:
functionUserProfile({ firstName, role = UserRole.SUBORDINATE }: UserProfileProps) {
if (role === UserRole.CTO) {
return<div>Hey Pat, you're AWESOME!!</div>
}
return<div>Hi {firstName}, you suck!</div>
}
Хуки
useState()
useState– Найпопулярніший хук React. У багатьох випадках його не слід типізувати. TypeScript здатний вивести типи значень, що повертаються useState() на основі початкового значення:
functionUserProfile({ firstName, role }: UserProfileProps) {
const [isFired, setIsFired] = useState(false);
return (
<><div>Hi {firstName}, you suck!</div><buttononClick={() => setIsFired(!isFired)}>
{isFired ? "Oops, hire them back!" : "Fire this loser!"}
</button></>
);
}
Тепер ми в безпеці. При спробі оновити стан не логічним значенням отримуємо помилку:
У деяких випадках TypeSctipt не може вивести тип значень, що повертаються useState():
// TS не знає, элементи якого типу будуть у масивуconst [names, setNames] = useState([]);
// початковим значенням є `undefined`, тому TypeScript-у невідом справжній типconst [user, setUser] = useState();
// теж саме справедливо для `null` в якості початкового значенняconst user = useState(null);
useState()реалізовано за допомогою загального типу (дженерика, generic type). Ми можемо використовувати це для типізації стану:
Композиція компонентів, від якої ми всі в захваті, передбачає передачу пропа children:
type LayoutProps = {
children: React.ReactNode;
};
functionLayout({ children }: LayoutProps) {
return<div>{children}</div>;
}
Тип React.ReactNodeнадає більшу свободу вибору переданого значення. Він дозволяє передавати майже будь-що (крім об’єкта):
Якщо як props повиннa передаватися тільки розмітка, тип childrenможна обмежити до React.ReactElementабо JSX.Element(що по суті те саме):
type LayoutProps = {
children: React.ReactElement; // чи `JSX.Element`
};
Ці типи є набагато суворішими:
Сторонні бібліотеки
Додавання типів
Сьогодні багато сторонніх бібліотек містять відповідні типи. У цьому випадку окремий пакет (з типами) не потрібно встановлювати.
Типи для великої кількості існуючих бібліотек містяться в репозиторії DefinitelyTyped на GitHub і публікуються під егідою організації @types(включаючи типи React). При встановленні пакета без типів та його імпорті отримуємо таку помилку:
Копіюємо виділену команду та виконуємо її в терміналі:
npm i --save-dev @types/styled-components
Якщо ви все ж таки зіткнулися з відсутністю типів для сторонньої бібліотеки, доведеться визначити глобальні типи самостійно у файлі .d.ts(ми не розглядатимемо його в рамках статті).
Використання дженериків
Бібліотеки розраховані на різні випадки використання, тому вони мають бути гнучкими. Для забезпечення гнучкості типів використовуються дженерики. Ми їх уже бачили в useState():
const [names, setNames] = useState<string[]>([]);
Такий прийом дуже поширеним для сторонніх бібліотек. Приклад з Axios:
Створення нового React-проекту з підтримкою TypeScript – справа однієї команди. Я рекомендую використовувати шаблони Vite+React+TS або Next.js+TS:
npm create vite [project-name] --template react-ts
npx create-next-app [project-name] --ts
Виявлення правильного типу
Ми це вже розглядали, але повторимо ще раз: починаємо писати вбудовану функцію та дозволяємо TypeScript вивести правильний тип події:
За наявності сумнівів щодо кількості доступних параметрів набираємо (...args) => та отримуємо відповідний масив:
Вивчення типу
Найпростіший спосіб отримати список всіх доступних полів типу – використовувати автозавершення в IDE. Для цього достатньо натиснути CTRL + Пробіл (Windows) або Option + Пробіл (Mac):
Щоб перейти до визначення типу, слід натиснути CTRL + Click (Windows) або CMD + Click (Mac):
Читання повідомлень про помилки
Повідомлення про помилки та попередження TS є дуже інформативними, головне – навчитися їх правильно читати. Розглянемо приклад:
Що це означає? Що ще за тип IntrinsicAttributes? При роботі з бібліотеками (у тому числі з самим React) ви часто зустрічатимете дивні назви типів, на кшталт цього.
Моя порада: ігноруйте їх спочатку.
Найважливішою частиною є останній рядок:
Property 'onChange' does not exist on type...
Дивимося на визначення компонента Input:
functionInput() {
return<input />;
}
У нього немає пропа onChange. Саме це “не подобається” TypeScript.
Нічого собі повідомлення про помилку! Без паніки: прокручуємо в кінець повідомлення – як правило, відповідь знаходиться там:
Перетини
Припустимо, що у нас є тип User, визначений в окремому файлі, наприклад types.ts:
export type User = {
firstName: string;
role: UserRole;
}
Він використовується для типізації пропов компонента UserProfile:
functionUserProfile({ firstName, role }: User) {
// ...
}
Який використовується в компоненті UserPage:
functionUserPage() {
const user = useFetchUser();
return<UserProfile {...user} />;
}
Поки все добре. Але що якщо UserProfile буде приймати ще один проп – функцію fireUser?
functionUserProfile({ firstName, role, fireUser }: User) {
return (
<><div>Hi {firstName}, you suck!</div><buttononClick={() => fireUser({ firstName, role })}>
Fire this loser!
</button></>
);
}
Отримуємо помилку:
Цю проблему можна вирішити за допомогою перетину (intersection type). При перетині всі поля двох типів поєднуються в один тип. Перетини створюються за допомогою символу &:
type User = {
firstName: string;
role: UserRole;
}
// `UserProfileProps` буде вміщувати в себе всі поля `User` та `fireUser`
type UserProfileProps = User & {
fireUser: (user: User) =>void;
}
functionUserProfile({ firstName, role, fireUser }: UserProfileProps) {
return (
<><div>Hi {firstName}, you suck!</div><buttononClick={() => fireUser({ firstName, role })}>
Fire this loser!
</button></>
);
}
Більш “чистим” способом є визначення окремих типів для компонентів, що приймаються props:
type User = {
firstName: string;
role: UserRole;
}
// !
type UserProfileProps = {
user: User;
fireUser: (user: User) =>void;
}
functionUserProfile({ user, onClick }: UserProfileProps) {
return (
<><div>Hi {user.firstName}, you suck!</div><buttononClick={() => fireUser(user)}>
Fire this loser!
</button></>
);
}
Як виправити проблему хука React useState, яка не встановлює початкове значення?
Хук useState дозволяє нам створювати зміни стану в наших компонентах React. Він приймає аргумент для початкового значення стану. Іноді нам може знадобитися встановити початкове значення стану з props. І ми хочемо оновити початкове значення, коли змінюється значення props.
У цій статті ми розглянемо, як виправити React хук useState з встановленням початкового стану з props.
Оновлення стану під час оновлення властивості
Щоб оновити стан, коли props оновлюється, ми маємо спостерігати за значенням props за допомогою useEffect хука. Потім у useEffect зворотному виклику ми можемо викликати функцію встановлення стану, щоб оновити значення стану значенням властивості. Наприклад, ми можемо написати:
У Count компоненті ми маємо useState хук зі count значенням як аргумент. Це встановлюється початкове значення count яке дорівнює num. Потім у нас є useEffect хук, який стежить за count значенням, передаючи його в масив у другому аргументі. Потім у зворотному виклику ми викликаємо, setNum щоб оновити num значення та відобразити його в операторі return під ним.
У App ми маємо стан count, створений хуком useState. Потім ми викликаємо setCount в обробнику onClick кнопки, яка оновлює значення count стану. І ми передаємо count значення як значення countprops у Count компоненті.
Тепер, коли ми натискаємо кнопку збільшення, ми бачимо оновлення значення num та його останнє значення.
Висновок
Ми можемо переконатися, що стан компонента React оновлюється, коли змінюється значення props, спостерігаючи за значенням props за допомогою useEffect хука, а потім викликаємо функцію встановлення стану у зворотному виклику useEffect зі значенням props як аргументом.
Потужність декораторів TypeScript на живих прикладах. Декорування методів класу.
Декоратори – інструмент декларативного програмування. З їх допомогою можна легко та елегантно додати до класів та членів класу метадані. На основі цих метаданих можна розширювати або змінювати поведінки класів та членів класу, не змінюючи при цьому кодову базу, до якої застосовано декоратор. Саму технологію можна віднести до мета-програмування чи декларативного програмування.
У рамках цієї статті розбирається кілька прикладів із реальних проектів, де застосування декораторів спростило код для розуміння і виключило його дублювання.
Яку проблему вирішують декоратори?
За допомогою декораторів ми можемо уникнути “дублювання” коду, інкапсулюючи наскрізну функціональність в окремий модуль. Забрати зайвий “шум” у коді, що дозволить сфокусуватися автору на бізнес логіці програми.
Наскрізна функціональність – функціональність, яка розподілена по всій кодовій базі. Як правило, ця функціональність не залежить від предметної галузі вашого проекту. До неї можна віднести такі приклади:
Логування
Кешування
Валідація
Форматування
і т.д.
Для роботи з наскрізною функціональністю існує ціла парадигма - Аспектно-орієнтоване програмування (AOP). Про її реалізацію в JavaScript раджу прочитати в цій чудовій статті . Так само існують чудові бібліотеки, що реалізують AOP JavaScript:
Якщо Вам цікава тема AOP, раджу поставити ці пакети та погратися з їхньою функціональністю.
У цій статті я спробував показати, як можна вирішити описані вище проблеми, вбудованої в TypeScript функціональністю — декоратори.
Для прочитання цієї статті передбачається, що ви маєте досвід використання react, mobx і typescript, т.к. я не вдаватимуся до подробиць цих технологій.
Трохи про декораторів загалом
У TypeScript декоратором є функція.
Форма застосування: @funcName . Де funcName – ім’я функції, що описує декоратор. Після прикріплення декоратора до члена класу, а потім його виклику, спочатку будуть виконуватися декоратори, а потім код класу. Однак декоратор може перервати потік виконання коду на своєму рівні, так що основний код класу в кінцевому рахунку не буде виконано. Якщо до члена класу прикріплено кілька декораторів, їх виконання відбувається зверху донизу по черзі.
Декоратори досі є експериментальною функцією TypeScript. Тому, для їх використання, вам потрібно додати до вашого tsconfig.json наступне налаштування :
target – об’єкт, для якого буде застосовано декоратор
key – ім’я методу класу, що декорується
descriptor – дескриптор методу класу.
За допомогою дескриптора ми можемо отримати доступ до вихідного методу об’єкта.
За допомогою шаблонної типізації можна виключити неправильне використання декоратора. Наприклад, ви можете обмежити застосування декоратора методами класу, у яких перший аргумент має строковий тип, визначивши тип дескриптора таким чином:
type TestDescriptor = TypedPropertyDescriptor<(id: string, ...args: any[]) => any>;
У наших прикладах ми використовуватимемо фабрики декораторів . Фабрика декораторів - це функція яка повертає викликану декоратором під час виконання функцію.
function format(pattern: string) {
// это фабрика декораторов и она возвращает функцию-декоратора
return function (target) {
// это декоратор. Здесь будет код,
// который что то делает с target и pattern
};
}
Підготовчі роботи
При розгляді прикладів нижче ми будемо використовувати 2 моделі даних:
export type Product = {
id: number;
title: string;
};
export type User = {
id: number;
firstName: string;
lastName: string;
maidenName: string;
}
У всіх функціях декораторів для дескриптора ми будемо використовувати тип PropertyDescriptor , який є еквівалентом TypedPropertyDescriptor<any> .
Додамо функцію-хелпер createDecorator, яка допоможе нам скоротити синтаксичний цукор створення декораторів:
export type CreateDecoratorAction = (self: T, originalMethod: Function, ...args: any[]) => Promise | void;
export function createDecorator(action: CreateDecoratorAction) {
return (target: T, key: string, descriptor: PropertyDescriptor) => {
const originalMethod = descriptor.value; // ссылка на оригинальный метод класса
// переопределяем метод класса
descriptor.value = async function (...args: any[]) {
const _this = this as T;
await action(_this, originalMethod, ...args);
};
};
}
Проект побудований на React + TypeScript . Для відображення стану програми на екран використовується чудова бібліотека Mobx . Нижче на прикладах я опущу пов’язані з Mobx частини коду, щоб сфокусувати вашу увагу на проблематики та її вирішення.
Спершу створимо клас AppStore, який міститиме в собі весь стан нашої маленької програми. Додаток складатиметься з двох списків – список користувачів та список товарів. Дані будуть використовуватися з сервісу dummyjson .
В результаті рендеру сторінки викликаються два запити на сервер для завантаження списків. AppStore виглядає так:
Зміна значень прапорців usersLoading і productsLoading контролює видимість індикаторів завантаження списку. Можна побачити в наведеному коді вище, ця функціональність методу повторюється. Спробуємо скористатися декораторами, щоб усунути це дублювання. Інкапсульуємо всі прапори завантаження в один об’єкт, який лежатиме як loading нашого сховища стану. Для цього визначимо інтерфейс і базовий клас (для повторного використання коду управління станом завантаження прапорів):
Якщо у вас немає можливості використовувати успадкування, можете використовувати інтерфейс ILoadable і реалізувати власний метод setLoading.
Тепер ізолюємо загальну функціональність контролю стану прапорів декоратор. Для цього створимо узагальнену фабрику створення декораторів loadable, використовуючи функцію хелпер createDecorator :
Фабрична функція є узагальненою та приймає на вхід ключі властивостей об’єкта, що лежатиме у властивості loading інтерфейсу ILoadable. Для коректного використання цього декоратора потрібно, щоб наш клас реалізував інтерфейс ILoadable. Скористаємося успадкуванням від класу Loadable, який вже реалізує цей інтерфейс і перепишемо код наступним чином:
Як тип для об’єкта як loading ми передаємо динамічно обчислюваний тип typeof defaultLoading від стану за умовчанням цього об’єкта — defaultLoading. Також, привласнюємо цей стан властивості loading. За рахунок цього, рядкові ключі, які ми передаємо в декоратор loadable, контролюється типізацією typescript. Як ви бачите, методи loadUsers та loadProducts краще читаються, а функціональність показу спіннерів інкапсульована в окремий модуль. Фабрика декораторів loadable та інтерфейс ILoadable абстраговані від конкретної реалізації стора і можуть використовуватися в необмеженій кількості сторін у додатку.
Обробка помилок у методі
Якщо раптом, з якоїсь причини, у наведеному вище прикладі сервіс dummyjson перестане бути доступним, наш додаток впаде з помилкою і користувач про це не дізнається. Давайте виправимо цю ситуацію
У кожному методі з’являється блок try…catch…, де обробка помилок відбувається в блоці catch. Спливає повідомлення у нижньому правому куті з текстом помилки. Скористайтеся силою декораторів та інкапсулюємо цю обробку в окремий модуль, зробивши її абстрактною:
Фабрична функція приймає на вхід необов’язкові параметри — кастомний заголовок та опис помилок, які будуть виводитися в повідомленні. Якщо параметри не будуть заповнені, буде використовуватися заголовок за промовчанням і повідомлення з поля message помилки. Використовуємо функцію errorHandle у нашому коді:
Фабрична функція приймає на вхід обов’язковий параметр повідомлення у повідомленні та не обов’язковий парметр опис повідомлення. Перепишемо код із використанням цієї функції:
Якщо ви збираєте дані вашої програми і потім проводите аналіз для його оптимізації та відстеження помилок, то вам необхідно додавати логи в код. Розглянемо приклад логування – виведення в консоль. Додамо логи до нашого сервісу без використання декоратора:
Як бачите, код у методах ускладнився для сприйняття та розуміння. І тут ще немає коду, який включає або відключає логи залежно від стейджу збірки або за будь-якими іншими критеріями, що зробить код ще складнішим. Створимо універсальний декоратор для логування.
export type LogPoint = "before" | "after" | "error" | "success";
let defaultLogPoint: LogPoint[] = ["before", "after", "error", "success"];
export function setDefaultLogPoint(logPoints: LogPoint[]) {
defaultLogPoint = logPoints;
}
export const log = (points = defaultLogPoint) =>
createDecorator(async (self, method, ...args) => {
try {
if (points.includes("before")) {
console.log(`Before calling the method ${method.name} with args: `, args);
}
const result = await method.call(self, ...args);
if (points.includes("success")) {
console.log(`The method ${method.name} worked successfully. Return value: ${result}`);
}
return result;
} catch (error) {
if (points.includes("error")) {
console.log(
`An exception occurred in the method ${method.name}. Exception message: `,
(error as Error).message
);
}
throw error;
} finally {
if (points.includes("after")) {
console.log(`The method ${method.name} completed`);
}
}
});
У цьому декораторі ми визначили точки для логування, які можна налаштовувати, передавши їх типізований масив у перший параметр фабрики декоратора. За промовчанням логується все. Також, функції setDefaultLogPoint можна перевизначити точки логування за промовчанням. Застосуємо цю фабрику в нашому коді:
Області застосування декораторів різноманітні та потенціал їх великий. З їхньою допомогою можна легко вирішити цілий спектр прикладних завдань, зробити код елегантним та простим для читання. Завдяки декораторам, ми можемо інкапсулювати повторюваний наскрізний функціонал у модулі, і перевикористовувати в інших частинах проекту або інших проектах. Однак у невмілих руках такий потужний інструмент може й нашкодити, наприклад, змінити пряме призначення методу. Але, на мій погляд, це не є підставою не вивчати та застосовувати цю технологію у своїх проектах. Декоратори стануть чудовим доповненням у ваших проектах як у ГО так і у функціональній парадигмі.
Розповім я вам одну історію. Якось я розробляв черговий компонент з вибором дати для нашої системи проектування. Компонент складається з поля для текстового введення та спливаючого календаря, що відображається при натисканні мишею по цьому полю. Потім календар, що випливає, можна закрити, клацнувши поза ним або якщо вибрано дату.
У більшості реалізацій такої логіки клацнути поза календарем застосовувалися конкретні слухачі подій, прикріплені до DOM. Але я хотів зробити наш компонент з вибором дати доступним так, щоб можна було відкривати календар із вкладками і таким же чином його закривати. Крім того, слухачі подій можуть вступати в конфлікт один з одним, якщо ви розмістите на сторінці кілька таких компонентів для вибору дати.
А якщо просто покластися на нативні події фокусування і розмиття, а не зв’язуватися з клацаннями поза полем? У такому разі, природно, підтримуються вкладки, події торкання та клацання, і все це вже реалізовано у браузері. Єдина проблема, яку доведеться вирішити в даному випадку, така: що робити, якщо ви клацаєте спливаючим полем, але без вибору дати. Тоді фокус переміщається на календар, в результаті з полем для введення відбувається розмиття, і зрештою спливаюче поле ховається.
Тут я задумався, а чи є спосіб зробити клацання, але не зрушувати фокус. Нашвидкуруч погуглив, я знайшов, як це зробити: придушити подію mouseDown, за замовчуванням спрацьовує для спливаючого поля. Все так: одного рядка вистачило, щоб усі клацання працювали, але поле для введення тексту залишалося у фокусі.
Здавалося: і все, рішення знайдено. Давайте рухатись далі. Але щось мене зупиняло. Чому саме mouseDown, а не mouseUp зупиняє фокус, але пропускає клацання? Це частина якогось чинного стандарту? Чи працюватиме це в кросбраузерному режимі? Бібліотека React Testing, за допомогою якої у нас робилися інтеграційні тести, також не підтримувала цієї можливості, тому мені довелося б змінювати функцію симуляції.
Що таке веб-стандарт?
Добре, оскільки відповіді зі Stack Overflow мені було недостатньо, то де ще шукати інформацію про поведінку веб-браузерів, як не в стандартних стандартах?
Ймовірно, ви чули про W3C , він же – Консорціум Всесвітньої Павутини. Це міжнародне співтовариство, яке розробляє відкриті стандарти для Інтернету. W3C прагне гарантувати, що всі керуються одними і тими самими нормами, і нам не доведеться підтримувати десятки різних оточень. Якщо зайдете на їхній сайт, то знайдете список усіх стандартів , над якими вони працюють.
Давайте заглянемо в один документ, де можуть бути відповіді на наші запитання – UI Events Standard(Стандарт подій інтерфейсу користувача). У цьому документі вказано потік подій DOM, визначено список подій та порядок їх виконання. Якщо вам здавалося, що веб-стандарти – це нудні, каламутні простирадла тексту, через які доводиться продиратися – одразу переходьте до розділу DOM Event Architecture (Архітектура подій DOM). Тут пояснено сплив подій, розказано про захоплення подій, а сам текст забезпечений веселими картинками. Проте це дуже конкретний документ, саме такий, яким і має бути стандарт. Вас здивує його якість, він насправді дуже якісно написаний, рясніє прикладами та рекомендаціями.
Також в ньому визначено і нашу подію mouseDown, зокрема, як вона діє за умовчанням:
“У багатьох реалізаціях подія мусила вживатися, щоб ініціювати ряд контекстно-залежних дій, що виконуються за умовчанням. Такі дії можна запобігти, якщо ця подія скасована. До таких дій, що виконуються за замовчуванням, можуть входити: початок перетягування, де об’єкт, що перетягується, – це зображення або посилання; початок виділення тексту, т. д. Крім того, в деяких реалізаціях передбачається можливість панорамування за допомогою миші, що активується, коли середня кнопка миші втоплена в момент диспетчеризації події, що минув.
Добре, для нашої події передбачені деякі дії за умовчанням, але в самій події фокусу немає нічого специфічного, оскільки фокус дійсно залежить від браузера. Давайте познайомимося з ними.
Знайомство з браузерними двигунами
Сучасний браузер – це дуже складний зразок софту з базою коду приблизно десятки мільйонів рядків . Тому браузер зазвичай ділиться на кілька частин.
Щоб визначити, де саме визначаються події фокусу, потрібно зробити огляд, який би дозволив зрозуміти, за що відповідає кожна частина. Почнемо з Chromium і документації щодо його проектування Getting Around The Chrome Source Code . Як бачите, тут безліч модулів і логіка, за яку відповідають модулі, у всіх модулів різна.
Давайте коротко розберемо їх усе, щоб зрозуміти, як взаємодіють усі ці компоненти.
chrome: це базова програма з логікою запуску, інтерфейсом користувача і всіма вікнами. Він містить проекти для chrome.exe та chrome.dll. Тут ви також знайдете ресурси, наприклад, іконки чи курсори.
content: це серверна частина програми, що обробляє комунікацію з дочірніми процесами.
net: це мережна бібліотека, яка допомагає виконувати запити на веб-сайти.
base: це місце для загального коду, що поділяється між усіма субпроектами. Сюди можуть бути включені такі речі, як операції над рядками, узагальнені утиліти, тощо.
blink: це двигун рендерингу, що відповідає за весь конвеєр відображення, у тому числі, за дерева DOM, стилі, події, інтеграцію з V8.
v8: остання більшість браузерного движка на JavaScript. Завдання цього компонента – компілювати JavaScript у нативний машинний код.
Як бачите, браузер складається з кількох незалежних частин, які спілкуються один з одним через API. З погляду розробника зазвичай найцікавіші Blink та V8. Дії за замовчуванням, що визначаються браузером, не входять до складу V8, але у Blink всі вони мають бути визначені та реалізовані. Але перш ніж переходити до бази коду Blink, давайте розберемося, як веб-браузери працюють з точки зору користувача.
Конвеєр візуалізації
Уявіть, що ви вводите в браузер адресу домену, а потім браузер вибирає та завантажує набір ресурсів: HTML, CSS, файли JS, зображення, ярлики. Але що має статися далі?
На першому кроці HTML-файли проходитимуть синтаксичний розбір і перетворюватимуться на дерево DOM . DOM – це не тільки внутрішнє уявлення сторінки, але й API, що відкривається JavaScript для виконання запитів і модифікації рендерингу за допомогою системи так званих «прив’язок».
Наступний крок після побудови дерева DOM – це обробка стилів CSS. Для цієї мети в браузерах є інструмент аналізу CSS, що збирає модель стильових правил. Побудувавши модель стильових правил, можна об’єднати їх із набором стилів, що задаються за замовчуванням (що надаються браузером) і обчислити остаточне значення кожної стильової властивості для кожного елемента DOM. Цей процес називається роздільною здатністю (або перерахунком) стилів .
У наступній частині описує макет , потрібно визначити візуальну геометрію для всіх елементів. На даному етапі кожен елемент отримує координати (x та y), ширину та висоту. Двигун компонування обчислює всі зони виходу за межі та веде їх облік – яка частина елемента буде видимою, а яка ні.
Коли у нас будуть всі координати для всіх елементів, настане час для відображення . Для цієї операції ми скористаємося координатами з попереднього кроку та кольорами із стильових правил, після чого скомбінуємо на їх основі список інструкцій з малювання. Важливо малювати елементи у правильному порядку, щоб, накладаючись одне одного, вони зберігали правильну «поверховість». Цей порядок можна змінити за допомогою стильового правила z-index.
Давайте виконаємо наші інструкції для відображення за списком і перетворимо їх на растр колірних значень. Цей етап називається розтеризацією . Саме зараз ми візьмемо наші зображення та декодуємо їх у карту бітів.
Пізніше розтеризована карта бітів зберігатиметься у пам’яті GPU. На даному етапі в роботу включаються бібліотеки, що абстрагують апаратне забезпечення та виклики до OpenGL і DirectX під Windows. Коли GPU отримує команди для відображення растрового малюнку, на дисплеї відображаються відповідні пікселі.
Ось у нас є всі найважливіші частини рендерингового конвеєра. Але що станеться, якщо прокрутити сторінку або застосувати на ній деяку анімацію? Насправді рендеринг не статичний. Для представлення змін використовуються анімаційні кадри. Кожен кадр повністю відображає стан контенту у конкретний час. Найскладніше при організації цього процесу – досягти потрібної продуктивності. Щоб анімація йшла гладко, необхідно генерувати щонайменше 60 кадрів на секунду. Провернути весь конвеєр 60 разів на секунду буде практично неможливо, особливо на повільних пристроях.
А що, якщо ми не будемо щоразу рендерити все заново, а надамо спосіб інвалідувати елемент на конкретному етапі. Скажімо, якщо ви динамічно змінюєте колір кнопки, то браузер помітить її вузол як інвалідний, і в наступному кадрі анімації її буде відображено заново. Якщо нічого не зміниться, ми зможемо повторно використовувати старий кадр.
Цей спосіб зручний для оптимізації невеликих динамічних змін вмісту. Давайте подумаємо, що робити, якщо потрібно змінювати великі області. Наприклад, після повного прокручування сторінки всі пікселі на новому екрані будуть іншими. Тому сторінка декомпонується на рівні, кожен із яких раструється незалежно. Рівень може бути дуже малий і представляти лише один вузол a DOM. Потім всі ці рівні комбінуватимуться в іншому потоці, який називається потік композитора . За такої оптимізації не доводиться повторно раструвати все відразу, достатньо виконувати ці операції для невеликих шарів, а потім правильно компонувати їх один з одним.
Отже, ми коротко розглянули, що робить Blink і як виглядає конвеєр рендерингу. Давайте заглибимося в код.
Навігація по базі коду Blink
Здається, ми наближаємося до фінішної прямої. Давайте відкриємо репозиторій Blink і розглянемо його.
Швидко стає зрозуміло, що, хоча ми змогли значно конкретизувати наше вихідне питання, масив коду поки що все одно занадто великий, щоб вручну знайти в ньому конкретний рядок, що відповідає за запобігання фокусу.
Давайте спробуємо пошукати в Google на ім’я події:
Приводить нас до файлу EventHandler , де можна знайти деталі реалізації для багатьох вхідних подій. У тому числі, той рядок, який нас найбільше цікавить.
Значення , що повертається dispatchMouseEventозначає «продовжувати обробляти так, як задано за замовчуванням», тому, у разі використання preventDefault, swallowEventдорівнює true.
Трохи нижче розташований виклик події фокусування, який спрацьовує лише у випадку, якщо swallowEvent == false.
Можете дослідити не тільки подію фокусування, але і всі дії, які задаються за умовчанням для події mouse down, у тому числі виділення, перетягування і роботу з повзунком. Також тут реалізуються подія відпускання кнопки миші та подія подвійного клацання.
Gecko і WebKit
Діставшись сюди, ми вже встигли чимало покопатися у вихідному коді браузерів і дуже непогано уявляємо собі їхню структуру. Так чому б не перевірити Firefox чи взагалі Safari. Двигун браузера Firefox називається Gecko, а двигун Safari – WebKit.
У Gecko також передбачена оглядова сторінка для розробників, тому легко усвідомити основні концепції цього движка. Спираючись на досвід роботи з Chrome, ви знайдете тут акуратний файл EventStateManager на 6000 рядків коду, в якому для подій задаються дії та стандартні поведінки.
WebKit– Це браузерний двигун від Apple, що використовується в Safari та інших продуктах Apple. Blink від Chrome є форком WebKit, тому у них багато спільного, і мені не важко знайти реалізації подій в їх версії файлу EventHandler .
Тепер, переконавшись, що можна безпечно придушити подію, що мусила встановити, я можу повернутися до початку цієї посади і спокійно доопрацювати інструмент для вибору дати.
Заключення
Разом ми пройшли шлях після простої проблеми до введення в веб-стандарти і розбору деталей, що стосуються реалізації браузерів.
Нехай вас не лякає прихована складність наявних модулів, що навіть стосуються браузера або компілятора. На Вас чекає захоплююча подорож. Ймовірно, ви легко знайдете, що тут можна було б покращити, і, що набагато важливіше, на власному досвіді набудете унікальних знань про те, як саме влаштовано. Особисто я перелопатив гору документації, працюючи над цим дослідженням, і рекомендую всім діяти так само. У всіх браузерах надається чудова документація, тому я справді не впевнений, а чи потрібно для роботи ще щось, крім неї.
Що таке шорт і лонг та як їх використовувати у торгівлі криптовалютами?
Головне
Шорти та лонги – короткі та довгі позиції (на продаж та на покупку) у трейдингу . Застосовуються головним чином під час маржинальної торгівлі, тобто торгівлі з плечем.
Більшість криптовалютних активів характерна висока волатильність. Використання шортів та лонгів дає можливість трейдерам отримувати прибуток у процесі цінових коливань.
При торгівлі в довгих і коротких позицій слід пам’ятати про хеджування — певні дії, спрямовані на захист від ситуацій, коли ринок рухається у протилежному напрямку відкритим позиціям.
Походження шортів та лонгів
У середньовічній Європі для обліку боргів використовувалися ціпки-бирки або лічильні палиці, що виготовляються з ліщини. На одній із граней бірки поперечними насічками позначали суму, що пускається в оборот, після чого розбирали бірку вздовж через насічки, але не повністю, а з відрубом в районі «рукоятки». В результаті виходила довга частина з рукояткою (stock) та коротка частина (foil), що доповнює цю довгу частину до повної палички. Насічки були на обох частинах. За збігом цих частин проводився контроль. Вважалося, що через фактуру ліщини підробка була неможлива. Дві частини зберігали дві сторони-учасниці транзакції. Із цієї практики, ймовірно, виникли терміни «фондовий ринок» (stock market), а також «лонг» (long) і «шорт» (short).
Висловлювання «короткі» і «довгі» позиції набули поширення на американських фондових і товарно-сировинних біржах 1850-ті роки. Можливо, найраніша згадка про короткі і довгі позиції присутня в журналі The Merchant’s Magazine, and Commercial Review, Vol. XXVI, за січень-червень 1852 року.
Незважаючи на назви, період для короткої позиції може бути досить довгим (тиждень, місяць), а період для лонга досить коротким. Зі світу традиційних фінансів терміни шорт і лонг перекочували в біткоін-індустрію.
Хто такі «бики» та «ведмеді»
Біржових гравців прийнято називати биками чи ведмедями залежно від того, якої стратегії вони йдуть. Тих, хто грає на підвищення (тобто тих, хто відкриває лонги), називають «биками», а гравців, які розміщують короткі позиції, тобто ставлять на зниження ринку — «ведмедями».
Ці терміни умовні: на крипторинці немає чистих бугаїв і ведмедів, часто один і той же трейдер одночасно торгує і в шорт, і в лонг, хоча обсяги позицій можуть відрізнятися.
Що таке лонг
Лонг (довга позиція) – купівля активу в очікуванні того, що він зросте в ціні. Розмір прибутку залежить від збільшення вартості активу. Довга позиція є найбільш популярним типом угоди у роздрібних інвесторів та використовуються на спотовому ринку.
Що таке шорт
Шорт простими словами – продаж фінансового інструменту в очікуванні, що він подешевшає.
Однак механіка короткої позиції дещо складніша за лонг. У рамках цієї схеми трейдер бере актив у борг і продає його на відкритому ринку за поточною ціною. Потім він чекає падіння курсу, купує ту кількість активу, яку брав у борг, за нижчим курсом і віддає борг із відсотками. Отриманий завдяки змінам цін прибуток трейдер залишає собі. У протилежному випадку, якщо ціна активу підвищиться, інвестор отримає збитки.
Приклад
У грудні 2017 року трейдер придбав біткоїни по $19 000 за монету. Він продав ці монети в той же період за $19 000, а потім виплатив позикодавцю приблизно $6000 за кожен BTC, коли в лютому 2018 року ціна значно знизилася . З кожної монети він отримав прибуток у $13 000.
До чого тут маржинальна торгівля
Якщо на спотовому ринку криптовалют можна, по суті, торгувати лише довгими позиціями (хоча і є прийоми, за логікою схожі на шортинг), то в маржинальній торгівлі стає можливим повноцінне відкриття коротких.
У рамках маржинальної торгівлі, яка дає можливість здійснювати угоди з плечем, користувач повинен надати заставу — внести на депозит суму (маржу), яка гарантує виплату боргових зобов’язань за встановленими біржею правилами.
Концепція маржі тісно пов’язана з концепцією левериджу або кредитного плеча (leverage) – множника, який збільшує доступний для операції депозит користувача за рахунок позикових коштів. На ринку криптовалют цей коефіцієнт може коливатися від 2:1 до 100:1 та більше. Тобто торгівля із плечем 50x означає, що при внесенні на депозит готівки на суму $100 ви можете відкрити позиції на суму до $5000.
Якщо ринкова вартість криптовалюти рухається в бік, що очікується трейдером, дохід збільшується пропорційно обраному кредитному плечу. У момент закриття такої позиції тіло застави повертається кредитору разом із комісійними зборами, а залишок отриманого прибутку зараховується на рахунок користувача.
Якщо ж ціна рухається у протилежному напрямку, то, як тільки вартість активів (і власних, і позикових) трейдера досягає розміру кредиту з відсотками (суми, яку трейдер має повернути кредитору), біржа автоматично ліквідує всі позиції гравця та повертає кредитору його кошти. У суму, яку кредитор повертає, повністю входить маржа.
У класичній торгівлі із плечем на фондовому ринку ліквідації позиції передує так званий маржин-кол — вимога додаткового забезпечення. Часто маржин-коллом називають безпосередньо момент ліквідації, на сленгу криптотрейдерів – “зловити моржа”.
Невдалу угоду трейдер може завершити самостійно, не чекаючи на ліквідацію. При цьому він втрачає не всю позицію, а лише частину маржі. Самостійно ліквідувати позицію можна вручну і за допомогою “стоп-лосса” (Stop Loss) – ордера для обмеження торгових ризиків, що передбачає автоматичне закриття угоди при досягненні певної цінової позначки.
Що таке хеджування?
На криптовалютному ринку застосовується механізм, відомий як хеджування — страхування на випадок, якщо тренд руху ціни активу не відповідає позиції трейдера. Наприклад, у вас відкрита довга позиція, а ціна криптовалюти знижується.
В основі хеджування – відкриття шорт-позицій, які врівноважують лонг-позиції та дозволяють залишитися «в нулі» при небажаній зміні ринкової ситуації. Інвестор залишає початкову лонг-позицію незайманою і відкриває шорт або ж використовує додаткові можливості.
Хеджування позиції — рішення для середньо- та довгострокової стратегії. Цей механізм дещо суперечить внутрішньоденному трейдингу, де переважають ринкові спекуляції. Популярний спосіб хеджування позицій передбачає використання ф’ючерсних контрактів: безстрокових та термінових.
Безстрокові контракти працюють за таким принципом: щовісім годин встановлюється так звана ставка фінансування. Останню учасники угод платять один одному замість того, щоб переказувати самі контракти або їх повні вартості. Залежно від ринкової ситуації платять ставку або власники лонг-контрактів власникам шортів, або навпаки.
Термінові контракти виконуються автоматично, якщо інвестор не закриває їх до дня експірації. Хеджуватися можна не лише ф’ючерсами, а й опціонами — похідними фінансовими інструментами для більш розвинених учасників ринку.
Що таке усереднення?
У рамках цієї стратегії інвестор скуповує актив за дедалі нижчою ціною, знижуючи тим самим середню вартість покупки.
Приклад
Ціна біткоїну досягла $29000, потім почала знижуватися. Побачивши фазу корекції, трейдер став купувати монети на послідовних рівнях зниження: $28000, $26000, $24000, $22000, $20000. Середня ціна покупки склала $24000. Після фази корекції курс почав зростати і згодом повернувся до рівня $29000 доларів.
Плюси та мінуси лонгів та шортів
Відкриття довгих позицій — зрозуміліша новачкові стратегія, яка зводиться до простого принципу «купуй дешевше, продавай дорожче».
Шортинг може бути ефективною інвестиційною стратегією, але набагато ризикованіший, ніж вкладення на тривалий термін або усереднення. Відкривати короткі позиції великі суми варто лише досвідченим трейдерам, здатним комплексно аналізувати ринкову динаміку.
Спробувати себе у криптотрейдінгу можна на криптобіржі Binance. На цей час це сама велика криптобіржа с великим вибором інструментів для торгівлі.
Всім профіту та будьте обережні при інвестуванні в крипту.
Крапка з комою в JavaScript: Чи дійсно вона вам потрібна?
У JavaScript крапки з комою є необов’язковими.
// Both statements work the same way
console.log("Hello")
console.log("Hello");
Однак є ситуації, в яких пропуск крапки з комою може призвести до небажаних наслідків. Тому немає однозначної відповіді на питання, чи слід використовувати крапку з комою, чи ні.
Використання крапок з комою завжди викликає суперечки у спільноті JavaScript. Існують вагомі аргументи на користь використання крапки з комою. Але також є вагомі причини, чому їх не слід застосовувати.
Це вичерпний посібник з використання крапок з комою в JavaScript.
Спочатку ми розглянемо правила використання крапок з комою у коді JavaScript. Потім ви дізнаєтеся, як працює автоматична вставка крапки з комою за кадром. І останнє, але не менш важливе: ви побачите список плюсів та мінусів використання крапок із комою.
Наприкінці цього посібника ви зможете вирішити, чи хочете ви використовувати крапки з комою чи ні.
Посібник з використання крапок з комою в JavaScript
Перш ніж обговорювати плюси та мінуси використання крапок із комою, необхідно зрозуміти, як вони взагалі використовуються.
Необхідне використання: Розділити два оператори в одному рядку
Якщо у вас є два оператори JavaScript в одному рядку, ви повинні поділити їх крапкою з комою. Можливо, найпоширенішим прикладом цього є цикл for.
Наприклад:
const numbers = [1, 2, 3, 4, 5];
for (let i = 0; i < numbers.length; i++) {
console.log(numbers[i]);
}
На виході:
1
2
3
4
5
Цикл for не буде працювати без крапки з комою, якщо його умова задається в одному рядку.
Необов’язкове використання: Крапки з комою як роздільники операторів
Крім поділу операторів для одного рядка, JavaScript немає інших обов’язкових випадків використання крапки з комою. Однак, за бажанням, ви можете використовувати крапки з комою для завершення оператора, навіть якщо були розриви рядків.
Ось кілька поширених прикладів операторів, які можна завершити крапкою з комою:
let i; // variable declaration
i = 5; // value assignment
let x = 9; // declaration and assignment
var fun = function() {...}; // function definition
alert("hi"); // function call
Пам’ятайте, що всі вищезгадані крапки з комою необов’язкові. Код працюватиме і без них.
Уникайте крапок із комою
Є ситуації, у яких слід уникати використання крапок із комою.
Уникайте крапок з комою після '}'. Не ставте крапку з комою після закриття фігурної дужки }.
Єдиним винятком є оператор присвоєння, наприклад, такий:
var data = {name: "Alice", age: 25};
У цьому випадку можна використовувати крапку з комою.
Ось кілька прикладів того, як не використовувати крапку з комою після фігурної дужки, що закриває:
if (...) {...} else {...}
for (...) {...}
while (...) {...}
function (arg) { /* actions */ }
Уникайте крапок з комою після ) в операторах if, for, while або switch.
У попередньому розділі ви дізналися, що не слід використовувати крапку з комою після закриття фігурної дужки. Однак якщо ви випадково це зробите, це буде просто проігноровано.
Жодної шкоди від цього не станеться. Але якщо ви поставите крапку з комою там, де її не повинно бути, то виникнуть проблеми.
Не додавайте крапку з комою після закриває дужки ) в:
операторів If
циклах For
циклах While
операторах Switch
Давайте розглянемо приклад того, чому важливо пам’ятати.
Якщо ви напишете оператор if наступним чином:
if (0 > 1); { console.log("Hello") }
Це еквівалентно наступному:
if (0 < 1);
console.log("Hello")
У цьому випадку він виводить повідомлення на консоль, хоча явно не повинен цього робити. Це тому, що крапка з комою повністю завершує оператор if. Потім блок коду, що йде за оператором if, виконується як окремий. Тому будьте обережні та не зловживайте крапкою з комою!
Винятки при використанні крапки з комою
Раніше у цій статті ви бачили приклад циклу for з крапкою з комою. Це винятковий випадок використання крапки з комою.
Погляньте на цей простий цикл:
for (let i = 0; i < 10 ; i++) { } // Works
Як ви можете бачити, крапка з комою не ставиться відразу після i++ .
Насправді після третього оператора в циклі for не можна ставити крапку з комою.
Якщо ви так зробите, то виникне синтаксична помилка:
for (let i = 0; i < 10 ; i++;) { } // SyntaxError
Це все, що вам потрібно знати, коли йдеться про правила використання крапок з комою в JavaScript.
Тепер давайте коротко обговоримо, чому використання крапок з комою в JavaScript необов’язкове.
Автоматична вставка крапки з комою у JavaScript
JavaScript не вимагає крапок з комою (за винятком одного виключення, яке ви бачили раніше).
Це відбувається тому, що JavaScript досить розумний і може автоматично додавати крапки з комою там, де потрібно.
Все відбувається “за лаштунками”, і ви нічого не помітите.
Парсер JavaScript додає крапку з комою в будь-якому з наступних випадків:
Наступний рядок коду починається з коду, який явно перериває поточний рядок коду.
Коли наступний рядок коду починається з }.
Досягши кінця файлу.
Якщо будь-який з наступних операторів зустрічається у вигляді окремого рядка
return (повернення)
break (перервати)
throw (викинути [помилку])
continue (продовжити)
Важливо розуміти, що ASI не завжди є коректним на 100%.
Крапка з комою використовується для поділу операторів на JavaScript, а не для їх завершення.
Це те, що ASI намагається зробити вас.
Якщо говорити простіше, то правила ASI можна сформулювати так:
Не кожне перенесення рядка вимагає крапки з комою. Однак розрив рядка, який не піддається парсингу без крапки з комою, потребує її використання.
Наприклад:
let x
x
=
10
console.log(x)
Цей фрагмент коду інтерпретується ASI як:
let x;
x = 10;
console.log(x);
В даному випадку ASI проробив відмінну роботу, зумівши розібратися в тому, як триває код між рядками 2-4.
Однак, іноді він може не знати, чого ми намагаємося досягти.
Наприклад, цей рядок коду призводить до помилки
const s = 'World'
const ab = "Hello" + s
[3].forEach(n => console.log(n))
В результаті виникає така помилка:
Uncaught TypeError: s[3].forEach is not a function
at :4:5
За описом помилки ви можете здогадатися, чому це відбувається.
Причина, через яку цей валідний фрагмент коду не працює, полягає в тому, що ASI не вставляє крапку з комою після другого рядка.
Натомість, він інтерпретує рядки 2 і 4 як продовження одного і того ж оператора наступним чином (відповідно до правила ASI номер 1):
const s = 'World';
const ab = "Hello" + s[3].forEach(n => console.log(n));
ASI думає, що s – це масив, і ви намагаєтеся отримати доступ до його 4 елемента за допомогою s [3] .
Але це не те, що ви плануєте здійснити.
Щоб змусити цей рядок працювати так, як очікується, необхідно вручну додати крапку з комою наприкінці другого рядка:
const s = 'World'
const ab = "Hello" + s;
[3].forEach(n => console.log(n)) // Prints '3'
Тепер код працює так, як передбачалося.
Інший приклад, коли ASI може викликати проблеми, – це оператори return.
Наприклад:
function getData() {
return
{
name: 'Bob'
}
}
console.log(getData())
На виході:
undefined
В результаті виводиться undefined, хоча малося на увазі, що з’явиться ім’я {name: 'Bob'}.
Так відбувається тому, що 4 правило ASI говорить, якщо оператор return зустрівся у вигляді окремого рядка, то ставиться крапка з комою.
Тому ASI бачить наведений вище код так:
function getData() {
return;
{
name: 'Bob'
}
}
console.log(getData())
Іншими словами, функція getData() нічого не повертає, а потім випадково створює об’єкт, з яким нічого не робить.
Таким чином, в консолі ви бачите undefined.
Для виправлення цього потрібно додати фігурну дужку, що відкриває, в той же рядок, що і оператор return:
function getData() {
return {
name: 'Bob'
}
}
console.log(getData())
На виході:
{
name: "Bob"
}
Тепер цей фрагмент коду працює як належить.
Завдяки цьому розділу ви навчилися бути обережними з ASI. Незважаючи на те, що в більшості випадків він діє правильно, іноді його інтерпретація ваших намірів може виявитися неправильною.
Далі перейдемо до найцікавішого, тобто до причин, з яких ви повинні або не повинні використовувати крапку з комою JavaScript.
Чому ви повинні використовувати крапку з комою: 5 причин
Використання або невикористання крапок із комою викликає спекотні суперечки серед веб-розробників.
Ось 5 причин, з яких ви повинні використовувати крапку з комою у своєму коді.
1. Іноді обов’язкова
Як було сказано раніше у цій статті, іноді необхідно використовувати крапку з комою.
Наприклад, якщо ви пишете цикл for, необхідно використовувати крапку з комою при вказівці параметра циклу та умов. В іншому випадку цикл не працюватиме.
Крім того, ASI (автоматична вставка крапки з комою) JavaScript не завжди відповідний на 100%.
Іноді він може неправильно витлумачити ваші наміри і не додати крапку з комою там, де вона потрібна. Це може призвести до появи непередбачених помилок у коді.
Один із таких прикладів ви також бачили раніше у цьому посібнику.
2. Ви звикли використовувати крапки з комою
Можливо, у процесі роботи ви звикли до використання крапок із комою в коді.
У деяких інших мовах широко використовуються крапки з комою, тому звикання до них є звичайною справою. Якщо ваш мозок не сприймає код JavaScript без крапок із комою, навіщо від них відмовлятися?
Не соромтеся використовувати крапки з комою, щоб зробити код більш зрозумілим для вас, якщо це те, що ви звикли робити.
3. Явно вказує на закінчення оператора
Крапка з комою – це простий спосіб чітко позначити закінчення оператора. При використанні крапки з комою немає місця для плутанини. Рядок коду закінчується на крапці з комою.
4. Менше приводів для занепокоєння
Якщо ви завжди використовуєте крапку з комою, то не варто переживати з приводу ASI. Це дає вам менше приводів для занепокоєння.
Після кожного рядка коду вам не потрібно замислюватися про те, чи зіпсує відсутність крапки з комою ситуацію чи ні. Однак ASI все одно може зіпсувати все, як ви бачили на прикладі оператора return .
5. ASI може бути змінено
Правила ASI можуть змінитися у майбутньому. Хоча це малоймовірно, але таке можливо. Таким чином, покладатися на правила ASI про вставку крапок з комою завжди за одним і тим же принципом надійно не на 100%.
Якщо ви пишете код з урахуванням поточного ASI, можете зіткнутися з деякими проблемами, якщо правила поміняються. Але майте на увазі, що у 99,9% випадків ASI виконує свою роботу коректно. Більше того, правила навряд чи зміняться найближчим часом.
Тепер, коли ви побачили безліч причин для використання крапок з комою, поговоримо про те, чому їх не слід використовувати.
Чому не слід використовувати крапки з комою: 3 причини
Зверніть увагу, що якщо ви чуєте, як хтось каже: “Ніколи не слід використовувати крапку з комою”, він помиляється. Це тому, що крапка з комою в окремих випадках обов’язкова.
У будь-якому випадку, поговоримо про мінуси крапок з комою, перерахувавши 3 причини, з яких їх не слід використовувати.
1. Крапки з комою вставляються автоматично
Як ви вже з’ясували, крапки з комою вставляються ASI. Таким чином, вам не потрібно писати те, що все одно буде проігноровано.
2. Менше написаного коду та менше шуму
Кожен символ коду впливає на читабельність та якість коду. Якщо ви не використовуєте крапки з комою, то цим заощадите символи в кожному написаному рядку коду.
3. Кілька операторів в одному рядку – погана практика
Використання крапок із комою дозволяє записувати по кілька операторів на одному рядку. Але це погана практика.
Ви ніколи не повинні писати оператори в одному рядку (якщо це не потрібно).
При використанні крапок з комою виникає ймовірність того, що у вас сформується ця погана звичка. Якщо ви не використовуєте крапки з комою, то можливості писати оператори в одному рядку у вас не буде.
Так використовувати крапки з комою чи ні?
Під час вивчення цієї статті ми обговорили причини, через які варто і не слід використовувати крапку з комою.
Як показує практика, є набагато більше причин для використання капок з комою, ніж для її відсутності. Таким чином, я рекомендую використовувати крапки з комою. Проте рішення лишається за вами.
Якщо ви працюєте в команді розробників програмного забезпечення, ви повинні дотримуватися загальноприйнятих правил. Якщо команда використовує крапки з комою, то і ви повинні їх застосовувати. Якщо команда цього не робить, то вам не слід їх ставити.
Також пам’ятайте, що потрібно бути послідовним у застосуванні крапок з комою та без них.
Якщо ви пропустили одну крапку з комою, то пропускайте їх усі (крім обов’язкових). Ви також можете налаштувати свій лінтер на автоматичне видалення крапок з комою.
Висновок
Сьогодні ви дізналися про використання крапок з комою у JavaScript. Нагадаємо, що крапки з комою не є обов’язковими у JavaScript. Водночас процес автоматичної вставки крапки з комою (ASI) додає крапки з комою там, де це необхідно.
Однак ASI не є правильним у 100% випадків. Крім того, у деяких ситуаціях ви просто зобов’язані використовувати крапку з комою. Інакше код не працюватиме.
Використовувати крапки з комою чи ні – повністю залежить від вас. На мій погляд, користі від використання крапок з комою більше, ніж від їхньої відсутності. Але ваша думка може відрізнятись.