MCPcopy Index your code
hub / github.com/max-mapper/art-of-node

github.com/max-mapper/art-of-node @main sqlite

repository ↗ · DeepWiki ↗
6 symbols 9 edges 4 files 0 documented · 0%
README

Поэзия Ноды

Введение в Node.js

Данный материал предназначен для читателей, которые уже имеют представление о:

  • скриптовых языках типа JavaScript, Ruby, Python, Perl и других. Если вы только начинаете программировать, то вам стоит начать с прочтения JavaScript for Cats. :cat2:
  • git и github. Эти инструменты для совместной работы широко используются в сообществе, чтобы делиться своими модулями. Вам достаточно знать хотя бы их основы. По ним есть отличные самоучители для новичков: 1, 2, 3

Оглавление

От переводчика

Несколько замечаний по переводу

В тексте будут встречаться английские слова и словосочетания. Такие термины я оставлял в скобках, чтобы читатель по мере прочтения привыкал к терминологии Ноды, и не привязывался к русским формулировкам, зачастую абсолютно без образным. Как правило это ключевые понятия типа "hard drive" или "event loop", которые опытный разработчик должен знать и так. А для начинающих так будет проще освоиться в тексте, чтобы у них не возникало двусмысленностей при чтении, когда одну и ту же вещь (образ) называют разными именами.

В некоторых местах я отклонялся от оригинального текста, меняя формулировку или же просто оставляя его без перевода. Часто это было по двум причинам 1. Я не понимал что хотел сказать автор и как перевести так, чтобы сохранился тот смысл, который он хотел передать 2. Я не видел большого смысла в написанном

С опытом вы всё чаще будете употреблять английские слова, произнося их по-русски, сокращая и даже коверкая. Со временем у вас выработается свой сленг, на котором вам будет удобно разговаривать с коллегами. Это нормально. Главное передать словом тот образ\суть, предмет разговора, а не вспоминать заученные формулировки на родном языке.

Благодарю авторов этой статьи http://frontender.info/art-of-node/ . В своем переводе я часто обращался к ней, чтобы сравнить или лучше понять смысл написанного. Это также перевод этой статьи, но авторы не стали выкладывать её на гитхаб.

Изучи Ноду интерактивно

В дополнение к чтению, очень важно параллельно писать код. Так вы скорее проникнетесь духом ноды и вникнете в её суть. Читать код в книге важно и нужно, но обучение через само написание кода - это ещё более лучший способ познания новых принципов программирования.

NodeSchool.io

NodeSchool.io серия открытых интерактивных воркшопов, по которым можно обучиться основным принципам Ноды.

Learn You The Node.js представляет собой вступительный воркшоп NodeSchool.io. Здесь собраны несколько задач, решение которых поможет тебе усвоить основные принципы построения программ для Ноды. Устанваливается как консольная утилита.

learnyounode

Устанавливается через npm:

# install
npm install learnyounode -g

# start the menu
learnyounode

Путь к пониманию Ноды

Node.js - опенсорсный проект, сделанный чтобы помочь тебе писать программы для работы с сетью, файловыми системами и другими I/O (input/output, reading/writing) на языке JavaScript. Вот и всё! Это простая и стабильная I/O платформа в которой удобно создавать свои модули.

Какие ещё есть примеры использования ввода/вывода (далее I/O)? Здесь показана схема приложения, к-ое я делал на Ноде; на ней видно какие могут быть I/O источники:

server diagram

Если ты не знаешь все источники представленные на схеме, ничего страшного. Суть в том, чтобы показать, что один единственный процесс Ноды (шестигранник в центре) может выполнять роль брокера (диспетчера) между разными конечными пунктами (endpoints) I/O (оранжевым и фиолетовым обозначены каналы ввода/вывода).

Обычно, построение систем такого вида складывается по одному из путей:

  • сложно для написания, но в результате получается супер-быстрая система (подобно написанию своих веб-серверов на чистом C)
  • просты в написании но сильно страдает в скорости работы (особенно, когда кто-то пытается отправить на сервер 5Гб файл и твой сервер падает)

Задача Ноды - сохранить равновесие при достижении двух целей: быть достаточно простым для понимания и использования и настолько же быстрым для решения большинства задач.

Нода не является: - веб-фреймворком (вроде Rails или Django, хотя и может использоваться для создания подобных вещей) - языком программирования (Нода использует JS, но сама Нода языком НЕ является)

Нода - нечто среднее, можно сказать, что Нода:

  • Сделана чтобы быть простой для понимания и использования
  • Удобной при создании I/O программ, которые должны работать быстро и оставаться устойчивой к высоким нагрузкам

На более низком уровне, Ноду можно назвать инструментом для написания двух типов программ:

  • Сетевые программы, использующие протоколы веба: HTTP, TCP, UDP, DNS и SSL
  • Программы, для чтения и записи данных в файловую систему (далее ФС) или локальные процессы/память

Что означает "программы для I/O" ("I/O based program")? Рассмотрим несколько основых источников Ввода/Вывода (I/O sources):

  • Базы данных (MySQL, PostgreSQL, MongoDB, Redis, CouchDB)
  • Внешние API (Twitter, Facebook, Apple Push Notifications)
  • HTTP/WebSocket соединения (от пользователей веб-приложений)
  • Файлы (сжатие изображений, редактирование видео, интернет-радио)

Нода выполняет операции ввода/вывода способом, к-ый называют асинхронным asynchronous. Такой способ позволяет ей выполнять много разных операций одновременно (simultaneously). Приведу небольшой пример для большего понимания. Например, зайдя в какой-нибудь фаст-фуд и заказав чизбургер, ваш заказ примут сразу, и после небольшой задержки ваш заказ будет готов. Пока вы ждете, они могут принимать другие заказы и начать готовить чизбургеры для других людей. А теперь представьте ситуацию, когда остальным людям в очереди приходится ждать пока вам не принесут чизбургер. Они даже не смогут сделать заказ, пока вам его не приготовят! Технически такое поведение называется блокирующая очередь, ведь все операции ввода/вывода (по приготовлению чизбургеров) происходят строго по одной в 1 момент времени. Нода же, наоборот, реализует механизм неблокирующей очереди, что позволяет готовить много чизбургеров одновременно.

На Ноде такие вещи можно реализовать довольно легко, благодаря её неблокирующей сущности:

Базовые модули (Core modules)

Во-первых, установите Ноду себе на компьютер. Брать её лучше отсюда nodejs.org

У ноды есть небольшая группа базовых модулей (которую обычно называют одним термином 'Ядро Ноды' ('node core')), которые предоставлены, как внешний API для написания программ. Каждый модуль предназначен для своих целей: для работы с файловой системой есть модуль 'fs', для работы с сетями net (TCP), http, dgram (UDP).

Помимо модуля fs и сетевых модулей, есть и другие базовые модули. Для асинхронной работы с DNS-запросами есть модуль dns, os - для получения данных об ОСи, для выделения бинарных фрагентов памяти (a module for allocating binary chunks of memory called) есть buffer, модули для различного рода парсинга урлов, путей к файлам и вообще (url, querystring, path). Большинство из базовых модулей, если не все, служат для одной общей цели - написание быстрых (!) программ для работы с ФС или сетью.

Нода обрабатывает I/O-операции используя: колбэки, события, потоки и модули. Если ты знаешь как они работают, то сможешь разобраться в любом базовом модуле и понять как его правильно использовать.

Колбэки (Callbacks)

Это, пожалуй, самая важная часть всего гайда. Если хочешь понять как работает Нода - придется разобраться с колбэками. Колбэки используются в Ноде повсюду; это не открытие Ноды, они лишь часть языка JavaScript.

Итак, начнем с определения. Колбэки - функции, к-ые вызываются не сразу, по мере выполнения основного кода, а асинхронно (asynchronously), т.е. их выполнение (invoking) будет отложено. В отличие от привычного процедурного стиля написания и выполнения кода сверху вниз (top to bottom), асинхронные программы могут выполнять свои функции непоследовательно (не в порядке их написания), учитывая скорость выполнения предыдущих функций, например http-запросов или чтения с диска.

Поначалу такое отличие попросту сбивает с толку. Действительно, бывает трудно определить заранее, будет ли функция выполняться асинхронно или нет - во многом это зависит от контекста её выполнения. Разберем простой пример синхронного выполнения, где код будет выполняться последовательно сверху вниз:

var myNumber = 1
function addOne() { myNumber++ } // определяем функцию
addOne() // выполняем функцию
console.log(myNumber) // 2

В коде определяется функция и на след строке происходит её вызов, без задержек и пауз. Когда функция вызывается, myNumber сразу увеличится на 1. Мы уверены, что после вызова функции число станет равным 2. Это и есть предсказуемость синхронного кода - он всегда выполняется последовательно сверху вниз.

Нода же часто использует асинхронную модель выполнения кода. Давайте с помощью Ноды прочитаем число из файла number.txt (файл находится на диске, а значит будем использовать модуль fs - прим. перев.):

var fs = require('fs') // подключение модуля для работы с ФС
var myNumber = undefined // пока мы не знаем какое число записано в файле

function addOne() {
  fs.readFile('number.txt', function doneReading(err, fileContents) {
    myNumber = parseInt(fileContents)
    myNumber++
  })
}

addOne()

console.log(myNumber) // undefined -- эта строка выполнится до того, как будет прочитан файл!

Почему же после вызова функции мы получили undefined? Обратите внимание, в коде мы используем асинхронный метод fs.readFile. Обычно, такие функции, где идут операции чтения-записи на диск или работа с сетью, делают асинхронными. Когда же требуется обратиться к памяти напрямую или поиспользовать возможности процессора, то функции делают синхронными. Дело в том, что операции I/O невероятно медленные (reallyyy reallyyy sloowwww) (это относится не только к Ноде но и ко всем языкам и технологиям - прим. перев). Стоит сказать, что чтение с диска (hard drive) происходит медленнее чем из памяти (RAM) примерно в 100k раз.

Когда мы запустим эту программу, определение функций произойдет немедленно, но такая быстрота не относится к скорости их выполнения. Это ключевой принцип для понимания асинхронного программирования. Когда произойдет вызов addOne она следом запустит функцию readFile, но не будет ждать окончания её работы, а перейдет к следующей задаче. Если Ноде больше нечего выполнять она будет просто ждать окончания IO-операций чтобы закончить работу и выйти.

Далее, когда readFile прочитает файл (это может занять некоторое время от нескольких миллисекунд до нескольких секунд или даже минут, в зависимости от того как быстро происходит чтение с диска), следом будет выполняться функция doneReading, которая и выдаст содержимое файла (если чтение прошло успешно) или ошибку.

В нашей программе мы получили на выходе undefined потому что в нашем коде нет никаких явных указаний функции console.log дождаться окончания выполнения readFile перед тем как выводить число.

Если вы хотите, чтобы какой-то код гарантированно выполнился последовательно, сперва поместите этот код в функцию! Только после этого ты сможешь вызвать функцию (выполнить блок кода) там где тебе надо. Это должно подтолкнуть тебя давать функциям точные и понятные имена.

Важно запомнить, что колбэки - просто функции, но которые выполнятся не сразу, по мере чтения кода, а тогда когда произойдет определенное событие. Ключ к пониманию механизма коллбэков лежит в том, что ты никогда не узнаешь когда (в какой момент времени) закончится асинхронная операция (I/O), но ты будешь уверен в том, где (после какого события) операция закончится - на последней строке асинхронной функции (т.е. колбэка)! Порядок объявления колбэков не имеет никакого значения и не влияет на последовательность выполнения. Значение имеет только их логическая вложенность, иерархичность если хотите. Сперва ты разбиваешь свой код на функции (как обособленные части кода) и только потом используешь колбэки, чтобы описать зависмости между их вызовами.

Снова вернемся к программе. Метод fs.readFile, предлагаемый Нодой, выполняется асинхронно и требует много времени для своего выполнения. Рассмотрим происходящее детально: для выполнения функции требуется обратиться к ОСи, которой надо обратиться к ФС, которая живет на диске, который совершает тысячи оборотов в минуту. Диску надо задействовать магнитную головку (а это уже физический уровень, между прочим) чтобы прочитать данные и отправить их обратно по всем уровням нашей программе. Ты передаешь методу readFile функцию-колбэк, которая и будет вызвана после того как данные от ФС будут получены. Колбэк поместит полученные данные в переменную и только теперь вызовет твою функцию-коллбэк уже с имеющей значение переменной (не undefined). В этом случае переменная называется fileContents, т.к. в ней лежит содержимое всего файла.

Вспомните пример с заказом и очередью из 1 части. Во многих ресто

Core symbols most depended-on inside this repo

addOne
called by 1
code/2.js
addOne
called by 1
code/3.js
addOne
called by 1
code/1.js
takesOneSecond
called by 0
code/4.js
after
called by 0
code/4.js
logMyNumber
called by 0
code/3.js

Shape

Function 6

Languages

TypeScript100%

Modules by API surface

code/4.js2 symbols
code/3.js2 symbols
code/2.js1 symbols
code/1.js1 symbols

For agents

$ claude mcp add art-of-node \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact