Как NodeJS может быть «неблокирующим»?

14

Я изучаю NodeJS и просто хотел кое-что прояснить. В нескольких вводных руководствах и книгах уже очень рано они описали «неблокирующую» архитектуру Node - или, скорее, можно (и рекомендую весь смысл) кодировать неблокирующим образом.

Так, например, этот пример был приведен в книге, которую я читаю об асинхронном способе получения данных из базы данных.

http.createServer(function (req, res) {
  database.getInformation(function (data) {
      res.writeHead(200);
      res.end(data);
  });
});

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

У меня вопрос, что именно обрабатывает запрос к базе данных? Конечно, Нод должен блокировать, пока он это делает? Что заботится о запросе базы данных? Или, если Node ожидает асинхронный HTTP-запрос GET к внешнему ресурсу, что заботится об этом запросе, который позволяет Node продолжать обработку стека вызовов и быть «неблокирующим»?

анонимное
источник

Ответы:

17

Когда Node.js описывается как «неблокирующий», это конкретно означает, что его IO является неблокирующим. Узел использует libuv для обработки своего ввода-вывода в зависимости от платформы. В Windows он использует порты завершения ввода-вывода, в Unix - epoll / kqueue / select / etc. Таким образом, он выполняет неблокирующий IO-запрос (который может иметь фоновый мониторинг потока, но он никогда не подвергается JavaScript), и в результате он ставит его в очередь в цикле обработки событий, который вызывает обратный вызов JavaScript для основного (читай: только) Поток JavaScript.

Для баз данных это зависит от того, как написана библиотека. Если он использует HTTP для связи (как это делают некоторые базы данных NoSQL), то он может быть легко написан на чистом JavaScript с использованием стандартной httpбиблиотеки узлов . Если он делает это по-другому, ну, это до библиотеки. Он может быть написан на C / C ++ и использовать фоновые потоки, если эта абстракция никогда не будет доступна JavaScript.

Что касается вашего вопроса о том, что «обрабатывает» запрос к базе данных, в идеале все, что нужно сделать, - это отправить простое сообщение в библиотеку (например, оператор SQL или какой-либо другой запрос или запрос на подключение), и в этот момент ваш JavaScript продолжает пыхтеть Когда библиотека готова отправить сообщение обратно, она отправляет сообщение обратно в очередь событий узла, которая выполняет обратный вызов, позволяя запустить этот фрагмент кода.

ckknight
источник
Существует netпакет, когда http недоступен.
Флориан Маргейн
Детали, которые могут помочь. Узел использует двигатель V8 JS. Одной из лучших функций V8 является простота привязки процессов C / C ++ к вызовам JS. Функции JavaScript блокируют, но все, что делает функция, это вызывает что-то скрытое, что не блокируется. Затем другая функция JS отвечает, когда этот процесс завершен. JS-функции, блокирующие друг друга, означают, что у вас никогда не будет двух вещей, пытающихся что-то сделать, например, запланировать запись в одно и то же местоположение файла в одно и то же время, и я полагаю, что многопоточность требует управления. Всегда ясно, какой запрос был первым для постановки в очередь.
Эрик Реппен