Не существующее свойство: ошибка памяти EventEmitter вместо правильного сообщения об ошибке

В приложении JavaScript для NodeJS 6.10.2/SailsJS 0.12.13 я испытываю несколько месяцев странное поведение ошибки.

В контроллере Sails я пытаюсь получить свойство литерала:

console.log(someObject.someProperty);
console.log("I am still here!");

Однако в моем случае someObject есть undefined. Итак, я ожидаю получить ошибку, например "Не могу прочитать свойство someProperty из undefined". - а затем либо Node.js, чтобы полностью остановиться или код для продолжения (со следующим console.log).

Вместо этого код просто прекращает выполнение в этой точке, и я получаю странное предупреждение: "(node: 4822) Предупреждение: обнаружена возможная утечка памяти EventEmitter 11 добавлены слушатели. Используйте emitter.setMaxListeners(), чтобы увеличить лимит". Однако непредсказуемо, как часто эта ошибка возникает. Somethings только один раз, около 20 раз сразу после друг друга.

То, что я выяснил, так это то, что оно каким-то образом связано с вопросом, был ли уже ответ или нет. Рассмотрим следующее:

mySailsControllerFunction: function(req, res) {
    console.log(someObject.someProperty);
    console.log("I am still here!");
    res.json({"foo":"dahoo"});
   }

В результате получится Sending 500 ("Server Error") response: ReferenceError: someObject is not defined - именно то, что я ожидаю.

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

mySailsControllerFunction: function(req, res) {
        res.json({"foo":"dahoo"});
        setTimeout(function () {
          console.log("Yeah!");
          console.log(someObject.someProperty);
          console.log("I am still here!");
       },1000);
}

то я часто ничего не получаю: "Да!" отображается, но потом ничего не происходит. Ошибка прослушивателя событий иногда бывает, иногда нет. Очень странно.

Кроме того, и это довольно странно, проблема, похоже, как-то связана с временем, прошедшим с момента запуска Sails. Я помещаю код, который вы видите выше, в функцию контроллера Sails, которая вызывается сразу после повторного подключения клиентов. Затем я играл со значениями тайм-аута, перезапустив сервер Sails несколько раз. Результат: если я установил таймаут в 1 с, в 4 из 5 тестов, я получу правильное поведение ошибки. В течение 10 секунд он составляет около 50%, в течение 30 с ошибка всегда будет проигнорирована без выхода консоли.

Однако, если я поставил свой тестовый код вне контроллера Sails, я всегда получаю правильное поведение ошибки с помощью Node. Итак, я уверен, что это неправильное поведение Sails, а не Node.

Ответ 1

Для справки: я, наконец, решил эту проблему. В коде были какие-то скрытые, обработчики выходных процессов обработаны:

 process.on('exit', myErrorFunction.bind());
 process.on('SIGINT', myErrorFunction.bind());
 process.on('uncaughtException', myErrorFunction.bind());

Проблема заключалась в том, что функция, в которой находились эти строки, была привязана к cronjob. Итак, каждый раз, когда выполнялся cronjob, регистрировались новые обработчики. Итак, мое предположение выше (до vs. после ответа) было неправильным: на самом деле все работало до тех пор, пока cronjob не был выполнен в первый раз. С этого момента этого не произошло. И, в конце концов, предупреждение было уволено (правильно!).

Я бы никогда не узнал без этого ответа: Сделать node показать трассировку стека после предупреждения EventEmitter Вы должны добавить одну строку кода, чтобы получить трассировку стека:

process.on('warning', e => console.warn(e.stack));

Кроме того, говоря о трассировке стека: В ответе сервера Sails (api/api/response/serverError.js) удобно обращаться к нему следующим образом:

module.exports = function serverError (data, options) {
  console.log(data.stack);
  /* ... */
};

Ответ 2

Отказ от ответственности: я не знаю Паруса. Так что это может быть или не быть связано, но мой ответ может предложить ключ.

Из документации Sails: http://sailsjs.com/documentation/reference/response-res/res-json

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

Таким образом, когда вы используете res.json({"foo":"dahoo"});, Sails, вероятно, отправляет ответ клиенту, закрывая последовательность вызовов, который, если он использует Promises или какой-либо другой механизм асинхронизации, может как-то "усвоить" дополнительный код, как это было предложено выше. Это, вероятно, внутреннее кодирование в Sails, поэтому он не сразу становится очевидным со стороны. ПОЧЕМУ ваш второй блок кода не работает.

Итак, вы должны придерживаться первого шаблона: сначала войдите в свой ресурс и поместите res.json() в конец функции контроллера.