2015-11-19 15 views
8

Próbuję zaimplementować moduł dla błędów niestandardowych.Błędy niestandardowe i przechwytywanie bluebirda z ErrorClass prowadzą do niezamierzonego zachowania

powinna istnieć możliwość wystąpienia pojedynczego błędu wewnątrz require-zestawieniu aplikacji przy użyciu tego modułu:

var MyCustomError = require('custom-error')('MyCustomError'); 

Jest to moduł:

'use strict'; 

var _CACHE = {}; 

function initError(name) { 
    function CustomError(message) { 
    this.name = name; 
    this.message = message; 
    } 
    CustomError.prototype = Object.create(Error.prototype); 
    CustomError.prototype.constructor = CustomError; 
    _CACHE[name] = CustomError; 
} 

function createCustomError(name) { 
    if (!_CACHE[name]) { 
    initError(name); 
    } 
    return _CACHE[name]; 
} 

module.exports = createCustomError; 

require-one-liner powyżej działa do tej pory.

Teraz w mojej służbie, chcę nadrobić ten błąd wyraźnie:

var MyCustomError = require('custom-error')('MyCustomError') 
// ... 
return fooService.bar() 
    .catch(MyCustomError, function (error) { 
     logger.warn(error); 
     throw error; 
    }) 

Gdybym odrzucić obietnicę fooService.bar w moim teście rzucając MyCustomError to działa świetnie.

ALE, działa to tylko dlatego, że mój test i usługa używają w tym samym wystąpieniu z MyCustomError.

Na przykład, jeśli usunę mechanizm buforowania w moim module błędów niestandardowych, przechwycenie nie zostanie już osiągnięte/wykonane, ponieważ użytkownik nie rozumie, że dwa błędy są tego samego typu:

function createCustomError(name) { 
    //if (!_CACHE[name]) { 
    initError(name); 
    //} 
    return _CACHE[name]; 
} 

specyficzny kodeks postępowania Bluebird mieści się w catch_filter.js, można rzucić okiem right here.

Chociaż podejście to działa w mojej aplikacji, będzie to szybciej prowadzić do problemów, gdy wiele modułów korzysta z modułu niestandardowego błędu, a udostępnianie tych samych wystąpień nie jest już podawane.

Jak mogę dostać tej koncepcji i działa przez nie porównującego instancje, ale typ błędzie sama?

Cheers,
Christopher

Odpowiedz

3

I wreszcie przyszedł z nieco innego podejścia. Dla ludzi o podobnych poglądach jest to wynik:

ErrorFactory

var 
    vsprintf = require("sprintf-js").vsprintf; 

function CustomErrorFactory(code, name, httpCode, message) { 

    // Bluebird catcher 
    this.predicate = function (it) { 
    return it.code === code; 
    }; 

    this.new = function (messageParameters, details) { 
    return new CustomError(messageParameters, details); 
    }; 

    this.throw = function (messageParameters, details) { 
    throw new CustomError(messageParameters, details); 
    }; 

    function CustomError(messageParameters, details) { 
    this.code = code; 
    this.name = name; 
    this.message = vsprintf(message, messageParameters); 
    this.httpCode = httpCode; 
    this.details = details || {}; 

    // Important: Do not swallow the stacktrace that lead to here. 
    // @See http://stackoverflow.com/questions/8802845/inheriting-from-the-error-object-where-is-the-message-property 
    Error.captureStackTrace(this, CustomError); 
    } 

    // CustomError must be instance of the Error-Object 
    CustomError.prototype = Object.create(Error.prototype); 
    CustomError.prototype.constructor = CustomError; 
} 

module.exports = CustomErrorFactory; 

Błędy

var 
    ErrorFactory = require("./ErrorFactory"); 

function initErrors() { 
    return { 
    Parameter: { 
     Missing: new ErrorFactory('1x100', 'ParameterMissing', 400, 'Parameter "%s" missing'), 
     Invalid: new ErrorFactory('1x200', 'ParameterInvalid', 400, 'Parameter "%s" invalid') 
     //.. 
    }, 
    Access: { 
     NotAccessible: new ErrorFactory('3x100', 'AccessNotAccessible', 403, 'Resource "%s" is not accessible for "%s"'), 
     //.. 
    }, 
    // ... 
    Request: { 
     //.. 
    } 
    }; 
} 

module.exports = initErrors(); 

utworzyć oddzielny moduł zawierający te zajęcia.

Następnie w moim realizacji, mogę złapać błędy tak indywidualnie:

function foo(request, reply) { 

    return bluebird 
    .resolve(bar) 
    .then(reply) 

    .catch(Errors.Parameter.Missing.predicate, function() { 
     return reply(boom.badRequest()); 
    }) 

    .catch(Errors.Entity.NotFound.predicate, function() { 
     return reply({}).code(204); 
    }) 

    .catch(Errors.Entity.IllegalState.predicate, function (error) { 
     return reply(boom.badImplementation(error.message)); 
    }) 

    // any other error 
    .catch(function (error) { 
     return reply(boom.badImplementation(error.message)); 
    }); 
} 

rzucanie

Errors.Entity.IllegalState.throw(['foo', 'bar']); 
// or 
throw Errors.Entity.IllegalState.new(['foo', 'bar']); 

Wymagaj

Errors = require('errors'); // all 
EntityErors = require('errors').Entity; // one group 
EntityNotFoundError = require('errors').Entity.NotFound; // one particular 

Jedyne co mi jeszcze nie zrozumieć id, dlaczego trzeba użyć funkcji predykatu, a nie tylko przekazywać obiekt błędu do catc h-klauzula. Ale mogę z tym żyć.

3

można również użyć funkcji predykatywne z połowu

function isMyCustomError(f) { 
    return f instanceof Error && f.name === "MyCustomError"; 
} 
+0

Hi Esailija, ponieważ nie zalogowany kilka dni reputacja nie został automatycznie przypisane do ciebie. Na szczęście dla ciebie, ale skoro jesteś programistą bluebird, zasługujesz na to dość :) Kod: Nie rozumiem, w jaki sposób to zatwierdza obsługę? Mówisz o klasycznej obsłudze try-catch niezależnie od bluebird? –

+0

@ Christopher Będzie to dla bluebird tylko – Esailija

+0

Tak właśnie robię w powyższym przykładzie - jak "catch (Errors.Entity.IllegalState.predicate, ..)" –