Ответ 1
Во-первых, оба графика правильны, хотя первый из них немного устарел. Асинхронная часть Node.js использовалась как libev, libeio и libuv. Однако, поскольку libuv продвигался в течение последних нескольких лет, "[in] версия libv libev node -v0.9.0 была удалена", в результате чего libuv уход за Node.js 'целыми асинхронными процессами ввода-вывода (поэтому, конечно, цикл событий). Таким образом, современная версия архитектуры Node.js заменит "libeio" и "libev" на "libuv" (как на втором изображении).
Причина, по которой эти два графика отличаются по своей структуре, заключается в том, что они организованы с учетом разных точек зрения. График 1 представляет классификацию различных частей технологии Node.js от высокого уровня до низкого уровня (при этом она не подразумевает рабочий процесс); тогда как график 2 является фактическим рабочим процессом операции Node.js.
Поставить это в аналогии: допустим, вы пытаетесь представить разные части автомобиля, используя графики. Вы можете сделать это по-разному: вы можете организовать разные части по их классификациям/функциям (сценарий A), таким образом:
- система питания: двигатель, масло, охлаждение, выхлоп и т.д.
- система передачи: коробка передач, вал, узел сцепления, дифференциал и т.д.
- система подвески: рычаг управления, амортизатор, компоненты рулевого управления и т.д.
- ......
или вы также можете упорядочить фрагменты с помощью рабочего процесса (сценарий B):
- масло → двигатель → трансмиссия → дифференциал → подвеска → и т.д.
(Я не слишком подробно разбираюсь в автомобилях. Название частей и фактический рабочий процесс может быть неправильным. Это только перечисление поможет с пониманием.)
Теперь, поскольку средства, с помощью которых вы упорядочиваете фигуры, различны, порядок, в котором они отображаются, будет отличаться. Сценарий A похож на ваш график 1, а сценарий B похож на график 2.
Я не уверен, насколько вы понимаете, как работает Node.js, поэтому я дам краткий обзор различных частей, которые вписываются в архитектуру Node.js, прежде чем перейти к объяснению того, как они взаимодействуют друг с другом:
-
V8 - механизм JavaScript с открытым исходным кодом Google, который находится в браузерах Chrome/Chromium. Вместо интерпретации кода JavaScript на лету, как это делают обычные веб-браузеры, V8 переводит ваш JS-код в машинный код, чтобы он быстро вспыхивал. V8 написан на С++. Подробнее о том, как V8 работает здесь.
-
libuv - libuv первоначально разрабатывался для обеспечения асинхронного ввода-вывода, который включает асинхронные сокеты TCP и UDP, ( известный) цикл событий, асинхронное разрешение DNS, чтение/запись файловой системы и т.д. libuv написан на C. Вот хороший видео, чтобы узнать больше о libuv.
-
Другие низкоуровневые компоненты - c-ares, http парсер, OpenSSL, zlib и т.д., в основном написанные на C/С++.
-
Приложение - вот ваш код, модули и Node.js 'встроенные модули, написанные на JavaScript (или скомпилированы в JS через TypeScript, CoffeeScript и т.д.)
-
Связывание. Связывание в основном представляет собой обертку библиотеки, написанной на одном языке, и выставляет библиотеку кодам, написанным на другом языке, чтобы сообщить коды, написанные на разных языках.
Теперь первый график должен иметь смысл: сверху - ваше приложение (, модули и основные Node.js встроенные модули), написанные на JavaScript; внизу находятся внутренние компоненты Node.js, написанные на C/С++. Чтобы соединить их так, чтобы они могли общаться, вам нужны привязки. Таким образом, где Node.js привязки сидят: между высокоуровневым приложением и низкоуровневыми Node компонентами. Эти графики не обязательно представляют собой рабочий процесс; это просто классификация различных частей Node.js в зависимости от их отношений/функциональных возможностей друг с другом.
Второй график представляет собой фактический рабочий процесс приложения Node.js. Код, написанный в вашем приложении, скомпилирован V8. Код связывается с низкоуровневыми компонентами Node.js через привязки. Все события, записанные в вашем коде, регистрируются с помощью Node.js. Как только события запускаются, они помещаются в очередь очереди событий в соответствии с порядком их запуска. Пока в очереди событий остаются оставшиеся события, цикл событий продолжает собирать их, вызывать их функции обратного вызова и отправлять их в рабочие потоки для обработки. Как только функция обратного вызова будет выполнена, его обратный вызов снова отправляется в очередь событий, ожидая, что его снова заберут цикл событий.
Часть вашего путаницы может исходить из выбора технических терминов, используемых во втором графике. Если вы посмотрите внимательно, ниже "NODE.JS BINDINGS" говорит "(NODE API)", что, к сожалению, представляет собой две разные вещи. Node.js API - это интерфейс встроенных библиотек, а привязки, с точки зрения программного обеспечения, являются мостами между кодами, написанными на разных языках.
Надеюсь, это поможет.
Более точное представление внутренней структуры Node.js заключается в следующем:
(я загрузил эту картинку из источника в Интернете некоторое время назад, и я забыл, где он. Если картинка принадлежит вам, прокомментируйте, и я добавлю кредит внизу! Спасибо!)
Изменить: Недавно я написал более подробную статью по объяснению Node.js архитектуры с простой в понимании аналогией. Хотелось бы, чтобы это помогло!