Доступ до бази даних. Стек, масив та організація даних

JavaScript Stack from Scratch

Це російськомовна версія керівництва Джонатана Верекії ( @verekia). Оригінальне керівництво розташоване. Цей посібник постійно розвивається та доповнюється автором, надаючи читачам максимально свіжу та якісну інформацію. Текст оригінального посібника та код, що додається, будуть змінюватися з часом. Ми також намагатимемося підтримувати російськомовну версію в актуальному стані. Цей переклад відповідає англійській версії станом на . Ми будемо раді вашим

Ласкаво просимо до мого сучасного посібника зі стеку технологій JavaScript: Стек технологій JavaScript з нуля

Це мінімалістичний та практико-орієнтований посібник із застосування JavaScript технологій. Вам знадобляться загальні знання з програмування та основи JavaScript. Це посібник націлено на інтеграцію необхідних інструментівта надає максимально прості прикладидля кожного інструмента. Ви можете розглядати цей документ як можливість створити свій власний шаблонний проект із нуля.

Звичайно, вам не потрібні всі ці технології, якщо ви робите просту веб-сторінку з парою JS функцій (комбінації Browserify / Webpack + Babel + jQuery достатньо, щоб написати ES6 код у декількох файлах і скомпілювати все через командний рядок), але якщо ви збираєтеся створити масштабоване веб додаток, і вам потрібно все правильно налаштувати, то це керівництво відмінно вам підходить.

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

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

Приклади коду є в кожній частині, і ви можете запускати їх через yarn & yarn start або npm install & npm start . Я рекомендую писати все з нуля самостійно, слідуючи покроковим інструкціямкожного розділу.

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

Примітка: Порядок частин не завжди є обов'язковим. Наприклад, тестування / типізація можуть бути виконані до введення React. Досить складно переміщати або редагувати опубліковані розділи, оскільки доводиться вносити зміни до всіх частин, що слідують за ними. Можливо, коли все визначиться, я приведу всю документацію до зручнішого вигляду.

Код, наведений у прикладах, працює під Linux, MacOS та Windows.

Найбільш часто використовуваними у веб-програмуванні структурами даних є стек та черга. При цьому багато хто не знає цього дивовижного факту.

Стек

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

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

Як більш технологічний приклад стека можна навести операцію «Скасувати» ( Undo) у текстовому редакторі. Щоразу, коли текст вводиться текстовий редактор, він поміщається в стек. Найперша зміна тексту є дно стека; останнє - вершину. Якщо користувач хоче скасувати останню зміну, видаляється верх стека. Цей процес може повторюватися доти, доки не залишиться жодної зміни.

Операції стеку

Оскільки тепер у нас є концептуальна модель стека, давайте визначимо дві операції стеку:

  • push(data) - додає дані;
  • pop() — видаляє останні додані дані.

Реалізація стеку

Тепер напишемо код для стека.

Властивості стеку

Ми створимо конструктор з ім'ям Stack. Кожен екземпляр Stack матиме дві властивості: _size і _storage :

function Stack() ( this._size = 0; this._storage = (); )

this._storage - дозволяє кожному екземпляру Stack мати власний контейнер для зберігання даних; this._size відображає скільки разів дані були додані до поточної версії Stack . Якщо створюється новий екземпляр Stack і до сховища додаються дані, то this._size збільшиться до 1. Якщо дані знову додаються до стек, this._size збільшиться до 2. Якщо дані видаляються зі стека, this._size зменшується до 1.

Методи стеку

Визначимо методи, за допомогою яких можна додавати ( push) і видаляти ( pop) дані зі стека. Почнемо з додавання даних.

Метод push(data)

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

Вимоги до цього методу:

  1. Щоразу, коли ми додаємо дані, розмір стека має збільшуватися;
  2. Щоразу, коли ми додаємо дані, порядок стека повинен зберігати свою послідовність:

Stack.prototype.push = function(data) ( // збільшення розміру сховища var size = this._size++; // призначає розмір як ключ сховища // призначає дані як значення цього ключа this._storage = data; );

Оголошуємо змінну size і присвоюємо їй значення this._size ++. Встановлюємо змінну size як ключ this._storage , data - як значення відповідного ключа.

Якщо стек викликав push(data) п'ять разів, то розмір стека буде 5. Перше додавання даних до стек призначить цим даним ключ 1 в this._storage . П'ятий виклик push(data)дасть ключ 5 в this._storage . Ми тільки-но поставили порядок для наших даних.

Метод 2 із 2: pop()

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

Цілі для цього методу:

  1. використовувати поточний розмір стека, щоб отримати останні додані елементи;
  2. Видалити останні додані елементи;
  3. Зменшити _this._sizeна один;
  4. Повернути останні видалені дані.

Stack.prototype.pop = function() ( var size = this._size, deletedData; deletedData = this._storage; delete this._storage; this.size--; return deletedData; );

pop() виконує всі перелічені нами завдання. Ми повідомляємо дві змінні: size ініціалізується значенням розміру стека; deletedData призначається для останніх доданих у стек даних. Потім ми видаляємо пару ключ-значення останніх доданих елементів. Після цього ми зменшуємо розмір стека на 1 і повертаємо дані, які були видалені зі стека.

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

Але якщо ми виконаємо всі операції у зворотному порядку, виникає проблема. Розглянемо наступний сценарій: ми викликаємо pop(), а потім push(data). Розмір стека стає -1, потім 0. Але коректний розмір нашого стека 1.

Щоб вирішити цю проблему, ми додамо до pop() оператора if :

Stack.prototype.pop = function() ( var size = this._size, deletedData; if (size) ( deletedData = this._storage; delete this._storage; this._size--; return deletedData; ) );

Після додавання оператора if тіло коду виконується тільки тоді, коли в нашому сховищі є дані.

Повна реалізація стека

Наша реалізація стека завершена. Ось остаточний варіант коду:

function Stack() ( this._size = 0; this._storage = (); ) Stack.prototype.push = function(data) ( var size = ++this._size; this._storage = data; ); Stack.prototype.pop = function() ( var size = this._size, deletedData; if (size) ( deletedData = this._storage; delete this._storage; this._size--; return deletedData; ) );

Від стеку до черги

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

Черга

Подібно до стеку, черга є лінійною структурою даних. Але, на відміну від нього, з черги видаляються лише елементи, додані раніше за інших.

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

Клієнт, який одержав другий талон, буде обслужений другим. Якби наша система обслуговування працювала як стек, клієнт, який був доданий до стек першим, був би обслужений останнім.

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

Операції черги

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

  • enqueue(data) - додає елементи в чергу;
  • dequeue - видаляє найстаріші дані з черги.

Реалізація черги

Тепер напишемо код для черги.

Властивості черги

Для реалізації ми створимо конструктор з ім'ям Queue. Потім ми додамо три властивості: _oldestIndex, _newestIndex і _storage:

function Queue() ( this._oldestIndex = 1; this._newestIndex = 1; this._storage = (); )

Методи черги

Тепер ми створимо три методи, що поширюються на всі екземпляри черги: size(), enqueue(data) та dequeue(data).

Метод size()

Цілі цього методу:

  1. Повернути коректний розмір черги;
  2. Збережіть правильний діапазон ключів для черги.

Queue.prototype.size = function() ( return this._newestIndex - this._oldestIndex; );

Реалізація size() може здатися вам дуже простою, але ви швидко зрозумієте, що це не так. Давайте ненадовго повернемося до реалізації способу size() для стека.

Припустимо, що ми додаємо в стек п'ять тарілок. Розмір нашого стека - п'ять, і кожна тарілка має відповідний номер від 1 ( перша додана тарілка) до 5 ( остання додана тарілка). Якщо ми приберемо три тарілки, то у нас залишиться дві тарілки.

Ми можемо просто відняти три з п'яти, щоб отримати правильний розмір – два. Ось основний принцип для розміру стека: поточний розмір є коректним ключем, пов'язаним з номером тарілки у верхній частині стека (2) та іншої тарілки в стеку (1). Іншими словами, діапазон ключів завжди має межі від поточного розміру до одного.

Тепер давайте застосуємо цю реалізацію розміру стека для черги. Уявіть, що п'ять клієнтів отримали талони. Перший клієнт має талон із номером 1, п'ятий клієнт має талон із номером 5. У черзі клієнт із першим талоном обслуговується першим.

Уявімо, що перший клієнт обслужений і цей талон видаляється з черги. За аналогією зі стеком ми можемо отримати коректний розмір черги шляхом віднімання 1 з 5. У черзі нині є чотири необслужені талони. Тут і виникає проблема: розмір більше не відповідає номерам, вказаним на талонах. Якщо ми просто віднімемо 1 із 5, ми отримаємо розмір 4. Ми не можемо використовувати 4 для визначення поточного діапазону талонів, що залишилися в черзі. У черзі залишилися талони з номерами від 1 до 4 чи від 2 до 5? Відповідь неясна.

Ось для чого нам потрібні дві властивості _oldestIndex і _newestIndex. Уявіть собі, що наша система обслуговування клієнтів має дві системи видачі талонів:

  1. _newestIndex - для обслуговування клієнтів;
  2. _oldestIndex – для обслуговування співробітників.

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

  1. Клієнт бере талон. Номер талона, який витягується з _newestIndex, дорівнює 1. Наступний талон, доступний у системі обслуговування клієнтів, має номер 2;
  2. Співробітник не бере квиток, а поточний талон у системі обслуговування працівників має номер 1;
  3. Ми беремо поточний номер талону в системі обслуговування клієнтів (2) і віднімаємо з нього номер у системі співробітників (1), щоб отримати число 1. Число 1 є кількістю талонів у черзі, які ще не були видалені;
  4. Співробітник бере талон із системи обслуговування. Цей талон є талоном клієнта, який має бути обслужений. Талон, який був обслужений, витягується з _oldestIndex, тут відображається номер 1;
  5. Ми повторюємо крок 4 і тепер різниця дорівнює нулю — в черзі більше немає талонів;
  6. Тепер у нас є властивість ( _newestIndex), яке вказує найбільшу кількість (ключ ), призначену в черзі, та властивість ( _oldestIndex), яке вказує на перший порядковий номер (ключ ) в черзі.

Метод enqueue(data)

Для enqueue у нас є два завдання:

  1. Використовувати _newestIndex як ключ для this._storage і використовувати будь-які дані, що додаються, як значення цього ключа;
  2. Збільшити значення _newestIndex на 1.

Ми створимо наступну реалізацію enqueue(data):

Queue.prototype.enqueue = function(data) ( this._storage = data; this._newestIndex++; );

У першому рядку ми використовуємо this._newestIndex , щоб створити новий ключ для this._storage і надати йому значення data. this._newestIndex завжди починається з 1. У другому рядку коду, ми збільшуємо this._newestIndex на 1, і значення тепер дорівнює 2.

Метод dequeue()

Завдання для цього методу:

  1. Видалити старі елементи з черги;
  2. Збільшити _oldestIndex на один:

Queue.prototype.dequeue = function() ( var oldestIndex = this._oldestIndex, deletedData = this._storage; delete this._storage; this._oldestIndex++; return deletedData; );

У тілі dequeue() ми оголошуємо дві змінні. Першою змінною, oldestIndex , присвоюється поточне значення черги для this._oldestIndex . Другий змінний, deletedData , присвоюється значення, що міститься в this._storage .

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

Стек виклику функцій (Call stack in programming languages)

Як розглядати стек виклику функції (Call Stack) у тих мов програмування. Хочу сказати, що стек виклику не зовсім те, що демонструє більшість матеріалів. Щоб остаточно зрозуміти що таке стек виклику, необхідно повернутися до аз і розглянути, як працює стек виклику в операційній системі, чому саме так? Тому що не можна розглядати стек виклику функцій відірвано від фізичної пам'яті та можливістю управління нею і тим самим не треба забувати, що стек виклику функцій це не «віртуальна» операція, а конкретне місце в пам'яті, що виділяється операційною системою для виконання програмного коду функції, яка була запущена внутрішнім або зовнішнім API (будь то браузера, IDE або движка будь-якої мови).

Хочу визначити, що таке стека виклику функції в низькорівневих (low-level programming languages) мовами (Assembler, C++):

На прикладі Ci++:

(У сучасних низькорівневих мовах є сучасні бібліотеки що дозволяють підтримувати роботу ОВП і контролювати стек функції не фізично, а використанням виведення консолі: Poppy, Pantheios)

Крок 1: запуск лейауту коду.

У лейауті, крім самих інструкцій, знаходиться додаткова інформація (змінні, декларативні дані, додаткові технічні дані та …)

Отримавши першу інструкцію про запуск ОС починає будувати стек. Спочатку виділяє фізичне місце на кластерах пам'яті та заповнює його даними, але якими:

  1. Перший виклик якоїсь програмної інструкції походить від модуля ОС, цей запуск так і отримав назву рівень модуля (це перша інструкція, яка починає свою роботу з модуля пам'яті ОС) (наведено стандартну назву в мовах main());

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

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

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

Інструкція повернення дзвінка, це не місце виклику цієї функції, а наступна інструкція.

Сегмент стека (який ми зараз простотою називаємо стеком виклику) це окрема ділянка пам'яті, в якій зберігаються інструкції про повернення результатів викликаних функції. Використовується метод: хто прийшов останній - піде перший (LIFO).

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

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

Далі необхідно зрозуміти, як високорівневі мови реалізовують роботу стека виклику. Давайте розглянемо два випадки: мови, що використовують багатопотоковість і однопотокові мови. Чому саме такі варіанти? Тому що саме багатопоточність (multithreading) та однопоточність визначає взаємодію віртуальної та фізичної пам'яті ресурсу.

Мови, що використовують багатопоточність, розглянемо на прикладі Java.

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

У двигун java імплементована спеціальна колекція Stack, у якої є два методи push (додасть дані) і pop (видалити дані). Віртуальна машина Java веде запис усіх викликаних функцій і з кожним викликом функції створює StackTraceElement. Після завершення функції StackTraceElement знищується, тому інформація про стек викликів завжди актуальна. З допомогою методу getMethodName можна завжди отримати інформацію про метод верхнього елемента StackTraceElement, а значить про метод виклику функції.

На малюнку представлений стек виклику зі змінними та методами об'єктів, реалізованих у Java

Javascript: Javascript однопотоковий скриптовий мову використовує чергу функцій зворотного виклику (callback functions queue) з методом FIFO (перший прийшов-перший підеш).

Два варіанти взаємодії фізичної та віртуальної пам'яті у Javascript:

  1. Робота JS в браузері (цикл подій  - event loop з чергою виконуваних колбеків). За переповненням стека (знову ж того сегмента з інформацією про адресу повернення) тут стежить як ОС так і API браузера та V8 двигун JS. API Google Chrome має метод, який після 16 тис записів стек-кадрів (stack frames) видає повідомлення про переповнення стека. після цього браузер виводить повідомлення про помилку або неможливість отримати дані для повернення функції та очищення стека. (Джерело: ;)

Сам стек як і базові використовує LIFO, а черга колбеків - FIFO. Також у V8 імплементовані методи push і pop, декларація ідентична методам, реалізованим Java.

Таймери в JS

Методи Javascript, що використовують таймери, що використовують API OS і таймери, які працюють на API браузера. Таймери завжди пересувають виконання функції колбека в кінець стека викликів. Що це означає? Це означає, що в браузері виконуючи методи setTimeout, setInterva спочатку запускається таймер, а потім функція-колбек потрапляє в чергу очікування. Якщо в момент влучення колбека стек переповнений, колбеку доводиться чекати своєї черги. Таймери запущені поза браузером реалізовані на підставі або внутрішніх методів V8 або при зверненні до оточення API (API OS).

Особливістю мови Javascript є технологія ajax або інакше можливість надсилання асинхронних запитів (XMLHTTPRequest) та виконання будь-яких операцій без затримки виконання основного коду. XMLHTTPRequest може бути відправлений синхронно, але при цьому весь решта коду буде чекати або результату відправки запиту, що часом недоцільно. Технологія ajax реалізована виключно у браузерах, що робить виділяє Javascript із групи мов, які використовують async. Асинхронні запити в JS використовують цикл подій з чергою колбеків (event loop with callback queue). В інших мовах програмування теж є можливість запуску асинхронного коду (Python (asyncio), C#(async/await)), що дозволяє виконувати якісь операції без затримки виконання основних функцій, принципом тут також виступає цикл подій, де функція колбек міститься в чергу очікування. Принцип роботи черги - FIFO.

Отже, у вас і вашого партнера з'явилася чудова бізнес-ідея. Правильно?

Ви постійно додаєте в думці все нові та нові можливості.

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

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

І нарешті, одного прекрасного дня ви вирішили: "Зробимо це!". І ось ви вже намагаєтеся розібратися як реалізувати бізнес-логіку своєї програми, ту кілер-фічу, яка рухатиме продукт уперед. У вас є ідея, як це зробити, і ви знаєте, що здатні на це.

І ось ви кажете: “Готово! Працює!” Ви маєте успішний прототип! Залишилося тільки упаковати його в веб-додаток.

"Окей, зробимо сайт," кажете ви.

А лише потім ви розумієте, що для цього потрібно вибрати мову програмування; потрібно вибрати (сучасну) платформу; потрібно вибрати якісь (сучасні) фреймворки; потрібно налаштувати (і купити) сховище, бази даних та хостинг; необхідно забезпечити інтерфейс для адміністрування; Необхідно забезпечити контроль доступу та систему управління контентом. Ви хочете бути ощадливим (lean) та гнучким (agile). Ви хочете використовувати технології, які допоможуть вам бути успішним як у короткостроковій, так і довгостроковій перспективі. А вибрати їх далеко не завжди так просто.

Перед вами десятки та десятки архітектурних рішень, які необхідно ухвалити. І ви не хочете помилитися: потрібні технології, які дозволять вести швидку розробку, підтримують постійні ітерації, максимальну ефективність, швидкість, стійкість та багато іншого. Ви хочете бути ощадливим (lean) та гнучким (agile). Ви хочете використовувати технології, які допоможуть вам бути успішним як у короткостроковій, так і довгостроковій перспективі. А вибрати їх далеко не завжди так просто.

"Я перевантажений", кажете ви і відчуваєте себе перевантаженим. Енергія вже не та, що була на початку. Ви намагаєтеся зібратися з думками, але роботи надто багато.

Прототип повільно блякне та вмирає.

Пропозиція

Після того, як я закинув купу ідей із схожих причин, я вирішив спроектувати рішення для цієї проблеми. Я назвав цей проект 'Init' (або init.js).

Основна ідея - використовувати один проект для старту будь-якого проекту, дати можливість розробнику або технічному керівнику прийняти всі основні рішення за раз і отримати відповідний початковий шаблон на них. Я знаю, багато хто скаже “Не можна застосувати одне рішення до всіх проблем” (haters gonna hate). І вони, можливо, мають рацію. Але ми можемо постаратися створити відповідне в цілому рішення, і, на мій погляд, Init із цим завданням впорався.

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

    Компоненти

    Компонентне уявлення – одна з ключових характеристик будь-якої системи, оскільки вона дозволяє повторно використовувати компоненти програмного забезпечення у кількох проектах, що є основною метою Init. Але компонентне уявлення містить у собі побічний ефект – замінність, яка стане нашим основним союзником боротьби з різними проблемами, вирішення яких “майже” однаково.

    Простота розробки

    Якась проблема де-небудь має рішення, найкраще реалізоване на Brainf*ck. буде практично неможливою для написання, не кажучи вже про читання. Це буде коштувати вам часу та величезних зусиль. В цілому, ви повинні використовувати мови та платформи, які спрощують, а не ускладнюють розробку для вас (і тих, хто робитиме її пізніше).

    Спільнота

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

Я покажу, як приймав рішення при створенні Init, не забуваючи про ці цілі.

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

Але ці ідеї не були новими, чому ж вони стали такими популярними з приходом Node.js? Просте програмування, що не блокує, досягається декількома способами. Мабуть, найпростіший це використовувати зворотні виклики (callbacks) і цикл подій - event loop. У більшості мов це непросте завдання: якщо зворотні виклики це досить поширена функція, то цикл подій – ні, і в якийсь момент ви опиняєтеся у сутичці із зовнішніми бібліотеками (наприклад: Python, Tornado). Але в JavaScript зворотні виклики це частина мови, як і цикл подій, і кожен програміст, який хоча б пробував JavaScript, знайомий з ними (або як мінімум використовував їх, навіть якщо не до кінця розумів, що таке event loop).

Несподівано, будь-який стартап на Землі може повторно використовувати розробників (читай: ресурси) і на клієнтській і серверній стороні, вирішуючи кадрову проблему, “Нам потрібен гуру Пітона”.

Так, альтернативи JavaScript'у народжуються щодня, наприклад, CoffeeScript, TypeScript та мільйони мов, які компілюються в JavaScript. Ці альтернативи можуть бути корисними на етапах розробки (), але їм не вдасться замінити JavaScript у довгостроковій перспективі з двох причин: їхні спільноти ніколи не стануть більшими, і їх кращі можливості будуть реалізовані в ECMA Script (читай JavaScript). JavaScript це не мова асемблера, це високорівнева мова програмування з вихідним кодом, який ви можете зрозуміти, тому ви повинні зрозуміти його.

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

Мінімальний, простий та пропонує вам необхідний мінімальний набір для написання простого SPA. Ember.js - це повноцінний і професійний фреймворк для створення односторінкових додатків. У ньому більше можливостей, але й крива навченості крутіше.

Залежно від розміру програми, рішення може бути таким же простим, як аналіз відношення "функції, що використовуються / доступні функції". Воно дасть вам гарну підказку.

У випадку Init, я хотів покрити більшість сценаріїв, тому вибрав Backbone.js для простого створення SPA, з Backbone.Marionette.View для компонентизації. У такій схемі кожен компонент - це простий додаток, а кінцевий продукт може бути настільки комплексним, наскільки я захочу.

Стилізація – це теж велике завдання, але ми вкотре можемо розраховувати на фреймворки. Для CSS немає нічого кращого

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

На мій досвід (під яким далі розумітимемо повний цикл розробки на JavaScript) виконує всі перераховані вище завдання. Можливо, Ви десь із ним стикалися; мабуть, Ви переконані у його ефективності і навіть сперечалися з друзями з цього приводу. А самі куштували? У цьому пості я зроблю огляд JavaScript, розповім навіщо він Вам потрібен і як все це працює.

Чому я використовую JavaScript

Я веб-розробник з 1998 року. Тоді часто ми використовували Perl для серверної розробки, але вже тоді на стороні клієнта був JavaScript. З того часу серверні технології сильно змінилися: одна за одною нас накривали хвилі мов та технологій, таких як PHP, ASP, JSP, .NET, Ruby, Python та ін. Розробники стали усвідомлювати, що використання двох різних мов на клієнті та сервері все ускладнює .

На початку епохи PHP та ASP, коли шаблонізатори були лише в зачатковій стадії, розробники вбудовували код додатків прямо в HTML. Наприклад:

Або ще гірше:

У початківців існували типові проблеми з розумінням операторів у різних мовах, наприклад таких, як for або foreach. Більше того, написання подібного коду на сервері та на клієнті для обробки тих самих даних – незручно навіть сьогодні:

Перші спроби робити все однією мовою полягали у створенні клієнтських компонентів на сервері та компіляції їх у JavaScript. Це не працювало так, як очікувалося, і багато тих проектів провалилися (наприклад, ASP MVC, який замінив ASP.NET Web forms , і GWT , якому на зміну прийшов дуже сумнівний Polymer). Але сама по собі ідея була чудовою, а особливо: єдина мова на клієнті та сервері, що дозволяє нам повторно використовувати компоненти та засоби (ключове слово тут: засоби).

Рішення було простим: запустити JavaScript на сервері.

Односторінкові програми

При роботі з full-stack JavaScript часто доводиться створювати односторінкові програми (SPA). Багато веб-розробників жодного разу спокушалися спробувати себе в SPA. Ви коли-небудь порівнювали SPA та звичайну веб-додаток при мобільному з'єднанні? Різниця у відгуку близько десятків секунд.

(Примітка: деякі можуть з цим не погодитися. Twitter, наприклад,



Останні матеріали розділу:

Чому на Місяці немає життя?
Чому на Місяці немає життя?

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

Лінкор
Лінкор "Бісмарк" - залізний канцлер морів

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

Крутиться земля обертається як обертання землі навколо сонця і своєї осі
Крутиться земля обертається як обертання землі навколо сонця і своєї осі

Земля не стоїть на місці, а перебуває у безперервному русі. Завдяки тому, що вона обертається навколо Сонця, на планеті відбувається зміна часів.