Обработка асинхронных исключений в Javascript с помощью node.js
В настоящее время я работаю над приложением node.js, и у меня обычная проблема с асинхронным кодом.
Я внедряю сервисный сервер поверх HTTP-модуля Node.
Этот сервер поддерживает (экспресс как) маршруты. Например, у меня есть код, который выглядит так:
server.any("/someRoute",function(req,resp){
resp.end("this text is sent to clients via http")
});
Сервер должен быть в состоянии противостоять сбоям, я не хочу разбивать весь сервер, когда есть проблема в функции, переданной любому. Проблема возникает, когда я пишу код, который выглядит следующим образом:
server.any("/someRoute",function(req,resp){
setTimeout(function(){
throw new Error("This won't get caught");
},100);
});
Я не понимаю, как я могу поймать ошибку здесь. Я не хочу сбивать сервер из-за одного сбоя на стороне сервера, вместо этого я хочу обслуживать 500.
Единственные решения, которые мне удалось найти, на самом деле не выразительны. Я только придумал с помощью process.on("uncaughtException",callback)
и аналогичный код с использованием узла 0,8 Domains
(это частичное исправление, но Домены в настоящее время глючат, и это все еще не очень выразительно, так как мне приходится создавать домен для каждого дескриптора).
То, что я хотел бы достичь, является обязательным throw
действия от функции к области, идеальное решение - что-то вроде привязки всех сгенерированных ошибок от функции к определенной функции-обработчику.
Это возможно? Как лучше всего обрабатывать ошибки в этом случае?
Я хотел бы подчеркнуть, что он должен иметь возможность продолжать обслуживать запросы после неудачных запросов, и перезагрузка сервера при каждом запросе или создание доменов для каждого обработчика и отлов их необработанных исключений кажутся мне плохой идеей. Кроме того - я слышал, что обещания могут помочь мне (кое-что о throw
в обещаниях), может обещания помогут мне в этой ситуации?
1 ответ
Предупреждение: я бы не рекомендовал исходный ответ с использованием доменов, в будущем домены устарели, мне было очень интересно писать оригинальный ответ, но я больше не считаю его слишком уместным. Вместо этого - я предлагаю использовать источники событий и обещания, которые имеют лучшую обработку ошибок - здесь приведен ниже пример с обещаниями. Обещания, используемые здесь, Bluebird:
Promise.try(function(){
throw new Error("Something");
}).catch(function(err){
console.log(err.message); // logs "Something"
});
С таймаутом (обратите внимание, что мы должны вернуть Promise.delay):
Promise.try(function() {
return Promise.delay(1000).then(function(){
throw new Error("something");
});
}).catch(function(err){
console.log("caught "+err.message);
});
С общей функцией NodeJS:
var fs = Promise.promisifyAll("fs"); // creates readFileAsync that returns promise
fs.readFileAsync("myfile.txt").then(function(content){
console.log(content.toString()); // logs the file's contents
// can throw here and it'll catch it
}).catch(function(err){
console.log(err); // log any error from the `then` or the readFile operation
});
Этот подход является быстрым и безопасным, я рекомендую его выше приведенного ниже ответа, который использует домены, которые, скорее всего, здесь не останутся.
Я закончил с использованием доменов, я создал следующий файл, который я назвал mistake.js
который содержит следующий код:
var domain=require("domain");
module.exports = function(func){
var dom = domain.create();
return { "catch" :function(errHandle){
var args = arguments;
dom.on("error",function(err){
return errHandle(err);
}).run(function(){
func.call(null, args);
});
return this;
};
};
Вот пример использования:
var atry = require("./mistake.js");
atry(function() {
setTimeout(function(){
throw "something";
},1000);
}).catch(function(err){
console.log("caught "+err);
});
Это также работает как обычный улов для синхронного кода
atry(function() {
throw "something";
}).catch(function(err){
console.log("caught "+err);
});
Буду признателен за отзыв о решении
Кстати, в версии 0.8 очевидно, что когда вы ловите исключение в домене, оно все еще всплывает process.on("uncaughtException")
, Я имел дело с этим в моем process.on("uncaughtException")
с
if (typeof e !== "object" || !e["domain_thrown"]) {
Тем не менее, документация предлагает против process.on("uncaughtException")
тем не мение