2015-02-23 3 views
1

Используя express-generator он выплевывает некоторые обработки ошибок кода:Почему этот вызов node.js не запускается немедленно?

app.use('/', routes); 
app.use('/users', users); 

// catch 404 and forward to error handler 
app.use(function(req, res, next) { 
    var err = new Error('Not Found'); 
    err.status = 404; 
    next(err); 
}); 

// error handlers 

// development error handler 
// will print stacktrace 
if (app.get('env') === 'development') { 
    app.use(function(err, req, res, next) { 
     res.status(err.status || 500); 
     res.render('error', { 
      message: err.message, 
      error: err 
     }); 
    }); 
} 

В этом примере, если (по любой причине) мои маршруты сломаны или маршрут не найден, или любой другой, код возвращается чтобы сбросить 404 во втором блоке кода. Почему третий блок кода (обработчик 500) не выполняется сразу после того, как начинает выполняться второй блок кода (обработчик 404)?

Я думал, что способ обратного вызова node.js заключается в том, что функция начинает выполняться и продолжает выполняться в фоновом режиме, а затем следующий обратный вызов начинает выполняться в одно и то же время. Но, по-видимому, я немного смущен тем, как работают синхронные обратные вызовы. Является ли вышеуказанный код каким-то образом «ждать» до тех пор, пока код обработчика 404 не будет выполнен перед запуском обработчика ошибок 500?

ответ

1

Все операторы app.use() запускаются при инициализации вашего приложения. Каждый из них настроил обработчик промежуточного программного обеспечения. На данный момент они фактически не запускают обработчики, они просто регистрируют их в стеке промежуточного программного обеспечения Express. Если ни один обработчик перед ними не обрабатывает страницу, эти два последних обработчика промежуточных программ app.use() получат запрос по заказу по порядку, а второй только увидит запрос, если первый передает запрос на большее количество обработчиков.

Обработчик 404 установит статус на 404, а затем вызовет обработчик в стек промежуточного программного обеспечения. Это будет вашим последним оператором app.use(), который будет видеть, был ли статус уже установлен, а если нет, установите его на 500, но если он был ранее установлен в 404, он оставит его на этом. Затем он применит рендеринг по умолчанию для отсутствующей страницы, отображающей статус на странице.

Это средство наличия единственного места, где применяется рендеринг по умолчанию, но несколько мест, которые могли бы устанавливать ошибки.

Ничего из этого не имеет никакого отношения к асинхронному поведению. Следующий обработчик запроса в списке запускается только тогда, когда next() вызывается более ранним обработчиком запросов. Нет «ожидания». Вы можете думать о обработчике запросов 404, используя последний оператор app.use(), как вызов синхронной функции, когда он вызывает next(). Он просто говорит, что выполнить следующий обработчик запроса в цепочке прямо сейчас (который, как он знает, является тем, который обеспечивает рендеринг по умолчанию для кода состояния ошибки).


Это может быть полезно рассмотреть, как app.use() работает в Express.

Каждый вызов app.use() добавляет обработчик запроса в список. Когда приходит заданный HTTP-запрос, Express начинает с первого обработчика запроса в списке и проверяет, соответствуют ли параметры этого первого обработчика запроса в текущем запросе (например, соответствует ли путь или какие-либо другие параметры, установленные в списке app.use()). Если он совпадает, то он вызывает этот обработчик запросов. Если этот обработчик запросов не вызывает next(), чтобы у следующего обработчика запросов в списке есть шанс на запрос, тогда вся обработка выполняется, и Express предполагает, что первый обработчик запросов полностью обработал запрос. Если этот первый обработчик запросов не полностью обработал запрос (скажем, он просто проверял значение cookie в заголовке и хочет, чтобы обработка продолжалась для других обработчиков), тогда он вызовет next(). Это говорит экспресс, чтобы посмотреть на следующий обработчик app.use() в списке и посмотреть, соответствует ли он этому запросу.

Пока обработчик запросов не соответствует текущему запросу или каждому, который продолжает звонить next(), чтобы сохранить цепочку, Express продолжит движение по списку, ищущему обработчик запроса, чтобы обработать запрос и сгенерировать ответ сервера. В вашем конкретном примере вторым и последним запросом в цепочке является обработчик 404. Он предполагает, что если Express получил это далеко вниз по цепочке, то никакой обработчик еще не обработал этот запрос, поэтому он должен быть запросом страницы, которую этот сервер не предназначен для обработки. Таким образом, он устанавливает статус в 404. И потому, что рендеринг по умолчанию для страницы с ошибкой находится в самом последнем обработчике запросов, он вызывает next(), чтобы инициировать отображение последней страницы по умолчанию с ошибкой в ​​нем.


+0

@Jakobud - вы получили достаточное объяснение, чтобы ответить/объяснить свой вопрос или все еще есть вещи вам нужна помощь? – jfriend00

0

Только один поток в интерпретаторе запускает ваш код. Операции ввода-вывода выполняются одновременно, так что выполнение JS может продолжаться без блокировки ввода-вывода. Он называется асинхронным, поскольку время и последовательность выполнения обратного вызова не находятся под вашим прямым контролем. Две функции JavaScript не выполняются одновременно.

Ваш код выше будет работать полностью без либо функций обратного вызова. После запуска кода модуль http будет прослушивать запросы клиентов (как правило, вы не указали это выше). Обратные вызовы будут выполняться по мере необходимости в ответ на эти запросы клиентов. Они не работают все время в отдельных потоках и ждут данных. app.use просто регистрирует функции в стеке промежуточного программного обеспечения express. Когда запросы поступают в этом совпадении с указанными вами маршрутами (или нет), соответствующие вызовы вызываются по порядку. Вот почему вы должны позвонить next в ваше промежуточное ПО; если вы этого не сделаете, обработка этого объекта запроса прекратится (этот проект называется continuation passing style).

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

Смежные вопросы