Обработка асинхронных исключений Javascript с помощью node.js

В настоящее время я работаю над приложением node.js, и у меня возникает обычная проблема с асинхронным кодом.

Я внедряю сервер службы поверх Node HTTP-модуля.

Этот сервер поддерживает (выражать как) маршруты. Например, у меня есть код, который выглядит так:

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) и аналогичный код, используя Node 0.8 Domains (который является частичным средством правовой защиты, но домены в настоящее время не работают, и это все еще не очень выразительно, поскольку мне приходится создавать домен для каждая ручка).

То, что я хотел бы выполнить, - это привязка действий throw от функции к сфере, идеальное решение - это нечто вроде привязки всех брошенных ошибок от функции к определенной функции обработчика.

Возможно ли это? Какова наилучшая практика для обработки ошибок в этом случае?

Я хотел бы подчеркнуть, что он должен иметь возможность продолжать обслуживать запросы после неудачных запросов и перезапускать сервер по каждому запросу или создавать домены для каждого обработчика и ловить свои неперехваченные исключения, кажется мне плохой идеей. Кроме того, я слышал, что promises может мне помочь (что-то о throw в promises), может ли promises помочь мне в этой ситуации?

Ответ 1

Предупреждение. Я бы не рекомендовал оригинальный ответ, используя домены, домены устарели в будущем. Мне было очень весело писать оригинальный ответ, но я больше не считаю, что это слишком актуально. Вместо этого я предлагаю использовать излучатели событий и promises, которые имеют лучшую обработку ошибок - вот приведенный ниже пример с promises. Используемый здесь promises 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 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);
});

Он также работает как обычный catch для синхронного кода

atry(function() {
    throw "something";
}).catch(function(err){
    console.log("caught "+err);
});

Я был бы признателен за некоторые отзывы о решении

На стороне примечания, в v 0.8, видимо, когда вы поймаете исключение в домене, оно все еще пузырится до process.on("uncaughtException"). Я имел дело с этим в моем process.on("uncaughtException") с

 if (typeof e !== "object" || !e["domain_thrown"]) {

Однако документация предлагает против process.on("uncaughtException") каким-либо образом