Node.js блокирует цикл события?

Я пишу API, и я застрял в точке, где я смешиваю asynchronous и синхронный код в зависимости от входящего запроса, взгляните на приведенные ниже примеры.

routes.js

module.exports = [ { method: 'GET', path: '/', controller: 'main', action: 'main', description: 'lists the API functionality', access: 'auth' }, { method: 'POST', path: '/users', controller: 'users', action: 'create', description: 'creates a new user', fields: { fullName: { format: { min: 2, max: 64, minWords: 2, disableDoubleSpaces: true }, description: 'the full name of the new user', examples: 'Thomas Richards, Richard Jones, Michael J. Fox, Mike Vercoelen, John Johnson' }, email: { format: { min: 2, max: 64, maxWords: 1, match: 'email' }, description: 'the email address of the new user', examples: 'mike@grubt.com, lilly@gmail.com, thomas.richards@mail.com, peter@mymail.com' }, password: { format: { min: 2, max: 64 }, description: 'the password of the new user', examples: '123abcdfg, 7373kEjQjd, #8klKDNfk' } } } ]; 

файл routes.js в основном является очень важной частью API, он проверяет входящие данные, маршруты к правильному controllerу / действию и определяет, является ли метод общедоступным, или требует проверки подлинности (базовый auth).

апи-server.js

 var http = require('http'); var url = require('url'); var os = require('os'); var dns = require('dns'); var apiServer = module.exports; var routes = require('./routes.js'); // Routes file from above. var req, res, controller, action, serverInfo, httpServer; apiServer.start = function(){ prepare(function(){ httpServer = http.createServer(handleRequest).listen(3000); }); }; // // We need to do this function, we need the local ip address of the // server. We use this local ip address in logs (mongoDb) so we can // refer to the correct server. // function prepare(callback){ var serverName = os.hostname(); dns.lookup(serverName, function(error, address){ if(error){ throw error; } serverInfo = { name: serverName, address: address }; callback(); }); } function getRoute(){ // loops through routes array, and picks the correct one... } function getAuth(callback){ // parses headers, async authentication (mongoDB). } function getRequestData(callback){ // req.on('data') and req.on('end'), getting request data. } function parseRequestData(callback){ // parse request data at this point. } function validateRequestData(callback){ // loop through route fields (see routes.js) and validate this data with the ones // from the request. } function requireControllerAndCallAction(){ // do actual job. } function handleRequest(request, response){ req = request; res = response; req.route = getRoute(); // First step for a request, syncronous. if(req.route === false){ // 404... } // If in the routing schema access was "auth", // this route requires authentication, so do that... if(req.route.access === 'auth'){ getAuth(function(error, user){ if(error){ // 401 } else { req.user = user; } } } if(req.method === 'POST' || req.method === 'PUT'){ // Async functions. getRequestData(function(){ parseRequestData(function(){ validateRequestData(function(){ requireControllerAndCallAction(); }); }); }); } else { requireControllerAndCallAction(); } } 

Как вы можете видеть, некоторые функции являются асинхронными (getAuth, getRequestData), а некоторые являются синхронными (parseRequestData, validateRequestData).

Теперь вот что:

Запрос 1. приходит с методом POST, url ‘/ users’ и данными:

  • fullName = ‘Rick’
  • email: ‘rick @’
  • пароль: ‘a’

Таким образом, мы просматриваем рабочий процесс API:

  1. получить текущий маршрут (controller: пользователи, действие: создать), увидеть второй элемент массива в routes.js

  2. получить данные запроса и обратный вызов: a. проанализировать данные b. проверять данные

Теперь давайте IMAGINE, проверка данных займет 5 секунд (что замедляется, но только, например), и во время этой проверки новый запрос приходит, новый запрос не обрабатывается до тех пор, пока предыдущий не будет закончен правильно?

Если они были синхронными, и если они заняли 5 секунд, то да, для этого экземпляра сервера запросы будут заблокированы. Поэтому критически важно, чтобы блокировка вызовов (сеть, db, файловая система и т. Д.) Вызывала asynchronous вызов. Цикл событий должен содержать цикл или все блоки сервера.

http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop/

Ключевая строка из этой записи:

… однако все работает параллельно, кроме кода

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

«Ваш код», как правило, просто обрабатывает обратные вызовы из длинных вызовов ввода-вывода, обновляет ваше состояние и затем отключает другой вызов. Но в этом его красота – когда вы обновляете свое состояние, оно находится в главном цикле событий, поэтому нет необходимости в многопоточном доступе к «вашему» состоянию и коду. Отсутствие блокировки, отсутствие взаимоблокировок и т. Д. … но все преимущества асинхронного и параллельного ввода-вывода, которые являются дорогостоящей частью.

Другой ключевой момент (который 5 секунд работы без ввода-вывода упадет):

Помимо вызовов ввода / вывода, Node.js ожидает, что все запросы возвращаются быстро; например, интенсивная работа с ЦП должна быть разделена на другой процесс, с которым вы можете взаимодействовать, как с событиями, или используя абстракцию, такую ​​как WebWorkers.

Кроме того, ожидайте «auth» и «POST» | «ПУТЬ», когда-либо случится по той же просьбе? Если это так, у вас может быть проблема. getAuth выглядит как asynchronous, но затем вы сразу же переходите к проверке req.method. В этот момент getAuth все равно будет работать. Если вы хотите, чтобы POST и PUT были аутентифицированы, тогда этот блок асинхронных методов может быть обернут методом getAuth async.