[node.js] Node.js 모범 사례 예외 처리

며칠 전에 node.js를 시험해보기 시작했습니다. 내 프로그램에서 처리되지 않은 예외가있을 때마다 노드가 종료된다는 것을 깨달았습니다. 이것은 처리되지 않은 예외가 발생하고 컨테이너가 여전히 요청을 수신 할 수있을 때 작업자 스레드 만 죽는 곳에 노출 된 일반 서버 컨테이너와 다릅니다. 이것은 몇 가지 질문을 제기합니다.

  • 인가 process.on('uncaughtException')그것을 방지하는 유일한 효과적인 방법은?
  • process.on('uncaughtException')뿐만 아니라 비동기 프로세스를 실행하는 동안 처리되지 않은 예외를 잡을?
  • 포착되지 않은 예외의 경우에 활용할 수있는 이미 구축 된 모듈 (예 : 이메일 보내기 또는 파일 쓰기)이 있습니까?

node.js에서 포착되지 않은 예외를 처리하는 일반적인 모범 사례를 보여주는 포인터 / 기사를 고맙게 생각합니다.



답변

업데이트 : Joyent는 이제 자체 가이드를 가지고 있습니다. 다음 정보는 더 많은 요약입니다.

안전하게 “throwing”오류

문자 그대로 오류를 발생시키는 대신 가능한 한 잡히지 않은 오류를 피하는 것이 이상적입니다. 대신 코드 아키텍처에 따라 다음 방법 중 하나를 사용하여 오류를 안전하게 “throw”할 수 있습니다.

  • 동기 코드의 경우 오류가 발생하면 오류를 리턴하십시오.

    // Define divider as a syncrhonous function
    var divideSync = function(x,y) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by returning it
            return new Error("Can't divide by zero")
        }
        else {
            // no error occured, continue on
            return x/y
        }
    }
    
    // Divide 4/2
    var result = divideSync(4,2)
    // did an error occur?
    if ( result instanceof Error ) {
        // handle the error safely
        console.log('4/2=err', result)
    }
    else {
        // no error occured, continue on
        console.log('4/2='+result)
    }
    
    // Divide 4/0
    result = divideSync(4,0)
    // did an error occur?
    if ( result instanceof Error ) {
        // handle the error safely
        console.log('4/0=err', result)
    }
    else {
        // no error occured, continue on
        console.log('4/0='+result)
    }
  • 콜백 기반 (즉, 비동기) 코드의 경우 콜백의 첫 번째 인수 err는 오류가 발생 err하면 오류이고 오류가 발생하지 않으면 err입니다 null. 다른 인수는 다음과 같은 인수를 따릅니다 err.

    var divide = function(x,y,next) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by calling the completion callback
            // with the first argument being the error
            next(new Error("Can't divide by zero"))
        }
        else {
            // no error occured, continue on
            next(null, x/y)
        }
    }
    
    divide(4,2,function(err,result){
        // did an error occur?
        if ( err ) {
            // handle the error safely
            console.log('4/2=err', err)
        }
        else {
            // no error occured, continue on
            console.log('4/2='+result)
        }
    })
    
    divide(4,0,function(err,result){
        // did an error occur?
        if ( err ) {
            // handle the error safely
            console.log('4/0=err', err)
        }
        else {
            // no error occured, continue on
            console.log('4/0='+result)
        }
    })
  • 들어 다사 다난 오류가 대신 오류를 던지는 어디서나 발생할 수 있습니다 코드, 화재 error이벤트를 대신 :

    // Definite our Divider Event Emitter
    var events = require('events')
    var Divider = function(){
        events.EventEmitter.call(this)
    }
    require('util').inherits(Divider, events.EventEmitter)
    
    // Add the divide function
    Divider.prototype.divide = function(x,y){
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by emitting it
            var err = new Error("Can't divide by zero")
            this.emit('error', err)
        }
        else {
            // no error occured, continue on
            this.emit('divided', x, y, x/y)
        }
    
        // Chain
        return this;
    }
    
    // Create our divider and listen for errors
    var divider = new Divider()
    divider.on('error', function(err){
        // handle the error safely
        console.log(err)
    })
    divider.on('divided', function(x,y,result){
        console.log(x+'/'+y+'='+result)
    })
    
    // Divide
    divider.divide(4,2).divide(4,0)

안전하게 “잡기”오류

그러나 때때로 어딘가에 오류를 발생시키는 코드가있을 수 있습니다. 코드 아키텍처에 따라 다음 방법 중 하나를 사용하여이를 파악할 수 있습니다.

  • 오류가 발생한 위치를 알면 node.js 도메인 에서 해당 섹션을 래핑 할 수 있습니다.

    var d = require('domain').create()
    d.on('error', function(err){
        // handle the error safely
        console.log(err)
    })
    
    // catch the uncaught errors in this asynchronous or synchronous code block
    d.run(function(){
        // the asynchronous or synchronous code that we want to catch thrown errors on
        var err = new Error('example')
        throw err
    })
  • 오류가 발생하는 위치가 동기 코드임을 알고 어떤 이유로 든 도메인 (아마도 이전 버전의 노드)을 사용할 수없는 경우 try catch 문을 사용할 수 있습니다.

    // catch the uncaught errors in this synchronous code block
    // try catch statements only work on synchronous code
    try {
        // the synchronous code that we want to catch thrown errors on
        var err = new Error('example')
        throw err
    } catch (err) {
        // handle the error safely
        console.log(err)
    }

    그러나 try...catch비동기식으로 오류가 발생하지 않으므로 비동기 코드에서 사용하지 않도록주의하십시오 .

    try {
        setTimeout(function(){
            var err = new Error('example')
            throw err
        }, 1000)
    }
    catch (err) {
        // Example error won't be caught here... crashing our app
        // hence the need for domains
    }

    try..catch비동기 코드와 함께 작업하려는 경우 Node 7.4 이상을 실행할 때 async/await기본적으로 비동기 함수를 작성할 수 있습니다.

    주의해야 할 또 다른 사항 try...catch은 완료 콜백을 try명령문 내부에 다음과 같이 배치 할 위험이 있다는 것입니다 .

    var divide = function(x,y,next) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by calling the completion callback
            // with the first argument being the error
            next(new Error("Can't divide by zero"))
        }
        else {
            // no error occured, continue on
            next(null, x/y)
        }
    }
    
    var continueElsewhere = function(err, result){
            throw new Error('elsewhere has failed')
    }
    
    try {
            divide(4, 2, continueElsewhere)
            // ^ the execution of divide, and the execution of 
            //   continueElsewhere will be inside the try statement
    }
    catch (err) {
            console.log(err.stack)
            // ^ will output the "unexpected" result of: elsewhere has failed
    }

    코드가 복잡 해짐에 따라이 작업은 매우 쉽습니다. 따라서 도메인을 사용하거나 오류를 반환하여 (1) 비동기 코드에서 포착되지 않은 예외 (2) 원하지 않는 실행 캐치 실행 시도를 피하는 것이 가장 좋습니다. JavaScript의 비동기 이벤트-머신 스타일 대신 적절한 스레딩을 허용하는 언어에서는 문제가되지 않습니다.

  • 마지막으로, 도메인이나 try catch 문에 래핑되지 않은 장소에서 catch되지 않은 오류가 발생하는 경우 uncaughtException리스너 를 사용하여 응용 프로그램이 충돌 하지 않도록 할 수 있습니다 (그러나 그렇게하면 응용 프로그램을 알 수없는 상태로 만들 수 있음) ) :

    // catch the uncaught errors that weren't wrapped in a domain or try catch statement
    // do not use this in modules, but only in applications, as otherwise we could have multiple of these bound
    process.on('uncaughtException', function(err) {
        // handle the error safely
        console.log(err)
    })
    
    // the asynchronous or synchronous code that emits the otherwise uncaught error
    var err = new Error('example')
    throw err

답변

다음은 코드 예제 및 선택된 블로그 게시물의 인용문을 포함하여이 주제에 대한 여러 소스에서 요약 및 정리 한 것입니다. 모범 사례의 전체 목록은 여기에서 찾을 수 있습니다.


Node.JS 오류 처리 우수 사례


Number1 : 비동기 오류 처리에 약속 사용

TL; DR : 콜백 스타일에서 비동기 오류를 처리하는 것이 아마도 가장 빠른 방법 일 것입니다 (일명 운명의 피라미드). 코드에 줄 수있는 최고의 선물은 try-catch와 같이 매우 작고 친숙한 코드 구문을 제공하는 평판 좋은 약속 라이브러리를 사용하는 것입니다.

그렇지 않은 경우 : Node.JS 콜백 스타일, function (err, response)은 오류 코드와 캐주얼 코드, 과도한 중첩 및 어색한 코딩 패턴의 혼합으로 인해 유지 관리 할 수없는 코드에 유망한 방법입니다.

코드 예-양호

doWork()
.then(doWork)
.then(doError)
.then(doWork)
.catch(errorHandler)
.then(verify);

코드 예제 안티 패턴 – 콜백 스타일 오류 처리

getData(someParameter, function(err, result){
    if(err != null)
      //do something like calling the given callback function and pass the error
    getMoreData(a, function(err, result){
          if(err != null)
            //do something like calling the given callback function and pass the error
        getMoreData(b, function(c){
                getMoreData(d, function(e){
                    ...
                });
            });
        });
    });
});

블로그 인용구 : “약속에 문제가 있습니다.”
(블로그 pouchdb에서 키워드 “노드 약속”으로 11 위)

“… 그리고 실제로 콜백은 훨씬 더 사악한 일을합니다. 스택은 우리가 프로그래밍 언어에서 당연한 것으로 간주하는 스택을 박탈합니다. 스택없이 코드를 작성하는 것은 브레이크 페달없이 자동차를 운전하는 것과 매우 흡사합니다. . 당신이 그것을 도달하고 거기 때까지 당신이 그것을 필요로하는지 심하게 모르고 약속의 요점은 우리가 비동기 갔을 때 우리가 잃어버린 언어 기본 백업 제공하는 것입니다. 반환, 던져, 스택을하지만 약속을 활용하려면 약속을 올바르게 사용하는 방법을 알아야합니다.


Number2 : 기본 제공 오류 개체 만 사용

TL; DR : 오류를 문자열 또는 사용자 정의 유형으로 발생시키는 코드를 보는 것이 일반적입니다 . 이는 오류 처리 논리와 모듈 간의 상호 운용성을 복잡하게합니다. 약속 거부, 예외 발생 또는 오류 발생 여부 – Node.JS 내장 오류 개체를 사용하면 균일 성이 향상되고 오류 정보가 손실되지 않습니다.

그렇지 않은 경우 : 일부 모듈을 실행할 때 어떤 유형의 오류가 반환되는지 확실하지 않으면 향후 예외에 대해 추론하고 처리하기가 훨씬 어렵습니다. 심지어 가치를 정의하기 위해 사용자 정의 유형을 사용하면 스택 추적과 같은 중요한 오류 정보가 손실 될 수 있습니다!

코드 예-올바르게 수행

    //throwing an Error from typical function, whether sync or async
 if(!productToAdd)
 throw new Error("How can I add new product when no value provided?");

//'throwing' an Error from EventEmitter
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));

//'throwing' an Error from a Promise
 return new promise(function (resolve, reject) {
 DAL.getProduct(productToAdd.id).then((existingProduct) =>{
 if(existingProduct != null)
 return reject(new Error("Why fooling us and trying to add an existing product?"));

코드 예제 안티 패턴

//throwing a String lacks any stack trace information and other important properties
if(!productToAdd)
    throw ("How can I add new product when no value provided?");

블로그 인용문 : “문자열은 오류가 아닙니다”
(블로그에서 “Node.JS 오류 객체”라는 키워드로 6 위를 차지했습니다)

“… 오류 대신 문자열을 전달하면 모듈 간의 상호 운용성이 줄어 듭니다. 오류 확인 인스턴스를 수행하거나 오류에 대해 더 알고 싶은 API와의 계약을 위반합니다 . 오류 개체는 다음과 같습니다. 메시지를 생성자에게 전달하는 것 외에도 최신 JavaScript 엔진의 흥미로운 속성 .. “


3 번 : 운영 오류와 프로그래머 오류 구별

TL : DR : 작업 오류 (예 : API에 유효하지 않은 입력이 수신 됨)는 오류 영향을 완전히 이해하고 신중하게 처리 할 수있는 알려진 사례를 나타냅니다. 반면에 프로그래머 오류 (예 : 정의되지 않은 변수를 읽으려고하는 경우)는 응용 프로그램을 정상적으로 다시 시작해야한다는 알 수없는 코드 오류를 나타냅니다.

그렇지 않은 경우 : 오류가 발생하면 항상 응용 프로그램을 다시 시작할 수 있지만 사소하고 예측 된 오류 (작동 오류)로 인해 최대 5000 명의 온라인 사용자가 중단되는 이유는 무엇입니까? 반대의 경우도 이상적이지 않습니다. 알 수없는 문제 (프로그래머 오류)가 발생했을 때 응용 프로그램을 유지하면 예기치 않은 동작이 발생할 수 있습니다. 두 가지를 차별화하면 전술적으로 행동하고 균형 잡힌 접근법을 적용 할 수 있습니다.

코드 예-올바르게 수행

    //throwing an Error from typical function, whether sync or async
 if(!productToAdd)
 throw new Error("How can I add new product when no value provided?");

//'throwing' an Error from EventEmitter
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));

//'throwing' an Error from a Promise
 return new promise(function (resolve, reject) {
 DAL.getProduct(productToAdd.id).then((existingProduct) =>{
 if(existingProduct != null)
 return reject(new Error("Why fooling us and trying to add an existing product?"));

코드 예-오류를 작동 가능으로 표시 (신뢰할 수있는)

//marking an error object as operational 
var myError = new Error("How can I add new product when no value provided?");
myError.isOperational = true;

//or if you're using some centralized error factory (see other examples at the bullet "Use only the built-in Error object")
function appError(commonType, description, isOperational) {
    Error.call(this);
    Error.captureStackTrace(this);
    this.commonType = commonType;
    this.description = description;
    this.isOperational = isOperational;
};

throw new appError(errorManagement.commonErrors.InvalidInput, "Describe here what happened", true);

//error handling code within middleware
process.on('uncaughtException', function(error) {
    if(!error.isOperational)
        process.exit(1);
});

블로그 인용구 : “그렇지 않으면 상태를 위험에 빠뜨립니다”(블로그에서 “Node.JS uncaught exception”키워드에 대해 순위가 3 인 블로그)

… JavaScript에서 throw가 작동하는 방식의 본질 상, 참조를 유출하거나 정의되지 않은 다른 취성 상태를 만들지 않고 안전하게”중지 된 곳을 “찾을 수있는 방법은 거의 없습니다. 던진 오류 프로세스를 종료하는 것입니다 . 물론, 정상적인 웹 서버에서, 당신은 많은 연결이 열려있을 수 있습니다, 그리고 오류가 다른 사람에 의해 촉발 되었기 때문에 갑자기 그 아래를 종료하는 것이 합리적이 아니다. 더 나은 접근 방법이다 “다른 사람들이 정상적인 시간을 끝내도록하고 그 작업자의 새 요청을 듣지 못하게하고 오류를 발생시킨 요청에 오류 응답을 보냅니다.”


Number4 : 미들웨어를 통하지 않고 중앙에서 오류를 처리

TL; DR : 관리 대상 메일 및 로깅과 같은 오류 처리 논리는 오류가 발생할 때 모든 엔드 포인트 (예 : Express 미들웨어, 크론 작업, 단위 테스트)가 호출하는 중앙 집중식 전용 개체에 캡슐화되어야합니다.

그렇지 않으면 : 한 곳에서 오류를 처리하지 않으면 코드가 중복되어 잘못 처리 된 오류가 발생할 수 있습니다.

코드 예-일반적인 오류 흐름

//DAL layer, we don't handle errors here
DB.addDocument(newCustomer, (error, result) => {
    if (error)
        throw new Error("Great error explanation comes here", other useful parameters)
});

//API route code, we catch both sync and async errors and forward to the middleware
try {
    customerService.addNew(req.body).then(function (result) {
        res.status(200).json(result);
    }).catch((error) => {
        next(error)
    });
}
catch (error) {
    next(error);
}

//Error handling middleware, we delegate the handling to the centrzlied error handler
app.use(function (err, req, res, next) {
    errorHandler.handleError(err).then((isOperationalError) => {
        if (!isOperationalError)
            next(err);
    });
});

블로그 인용문 : “때때로 낮은 수준에서는 호출자에게 오류를 전파하는 것 외에는 유용한 기능을 수행 할 수 없습니다”(Joyent 블로그에서 키워드 “Node.JS 오류 처리”)

“… 여러 레벨의 스택에서 동일한 오류를 처리하게 될 수 있습니다. 이는 하위 수준이 오류를 호출자에게 전파하여 오류를 호출자에게 전파하는 것 외에는 유용한 작업을 수행 할 수 없을 때 발생합니다. 작업을 다시 시도하거나 사용자에게 오류를보고하는 등의 방법으로 최상위 응답자 만 적절한 응답을 알고 있지만 모든 오류를 단일 최상위 수준으로보고하려고하는 것은 아닙니다. 콜백 자체는 어떤 컨텍스트에서 오류가 발생했는지 알 수 없기 때문에 “


Number5 : Swagger를 사용하여 문서 API 오류

TL; DR : API 호출자에게 오류가 발생할 수있는 오류를 알려주므로 충돌없이 오류를 신중하게 처리 할 수 ​​있습니다. 일반적으로 Swagger와 같은 REST API 문서 프레임 워크를 사용하여 수행됩니다.

그렇지 않으면 : API 클라이언트는 이해할 수없는 오류를 수신했기 때문에 충돌 및 재시작을 결정할 수 있습니다. 참고 : API 호출자는 귀하 일 수 있습니다 (마이크로 서비스 환경에서 매우 일반적 임)

블로그 인용문 : “호출자에게 어떤 오류가 발생할 수 있는지 알려 주어야합니다”(Joyent 블로그에서 키워드 “Node.JS logging”에 대해 1 위)

… 오류를 처리하는 방법에 대해 이야기했지만 새 함수를 작성할 때 함수를 호출 한 코드에 오류를 어떻게 전달합니까? … 어떤 오류가 발생할 수 있는지 또는 무슨 뜻인지 모르는 경우 우연히 프로그램을 수정할 수 없습니다. 따라서 새로운 함수를 작성하는 경우 호출자에게 어떤 오류가 발생할 수 있고 어떤 조치를 취해야하는지 알려야합니다.


6 번 : 낯선 사람이 마을에 올 때 프로세스를 정상적으로 종료하십시오

TL; DR : 알 수없는 오류가 발생하면 (개발자 오류, 모범 사례 번호 3 참조)-응용 프로그램 상태에 대한 불확실성이 있습니다. 일반적으로 Forever 및 PM2와 같은 ‘다시 시작’도구를 사용하여 프로세스를 신중하게 다시 시작하는 것이 좋습니다.

그렇지 않은 경우 : 익숙하지 않은 예외가 발견되면 일부 오브젝트에 결함이있는 상태 (예 : 전역 적으로 사용되며 일부 내부 장애로 인해 더 이상 이벤트를 발생시키지 않는 이벤트 이미 터)에있을 수 있으며 이후의 모든 요청이 실패하거나 미치게 작동 할 수 있습니다.

코드 예-충돌 여부 결정

//deciding whether to crash when an uncaught exception arrives
//Assuming developers mark known operational errors with error.isOperational=true, read best practice #3
process.on('uncaughtException', function(error) {
 errorManagement.handler.handleError(error);
 if(!errorManagement.handler.isTrustedError(error))
 process.exit(1)
});


//centralized error handler encapsulates error-handling related logic 
function errorHandler(){
 this.handleError = function (error) {
 return logger.logError(err).then(sendMailToAdminIfCritical).then(saveInOpsQueueIfCritical).then(determineIfOperationalError);
 }

 this.isTrustedError = function(error)
 {
 return error.isOperational;
 }

블로그 인용문 : “오류 처리에 관한 세 가지 생각 학교가있다”(블로그 jsrecipes에서)

… 오류 처리에 대한 세 가지 생각 학교는 주로 다음과 같습니다. 1. 응용 프로그램이 중단 된 후 다시 시작합니다. 2. 가능한 모든 오류를 처리하고 충돌하지 마십시오. 3. 둘 사이의 균형 잡힌 접근


Number7 : 성숙한 로거를 사용하여 오류 가시성 향상

TL; DR : Winston, Bunyan 또는 Log4J와 같은 성숙한 로깅 도구 세트는 오류 발견 및 이해 속도를 높입니다. 따라서 console.log는 잊어 버리십시오.

그렇지 않은 경우 : console.logs를 통해 감추거나 쿼리 도구 나 적절한 로그 뷰어를 사용하지 않고 지저분한 텍스트 파일을 통해 수동으로 늦게까지 업무에 바쁠 수 있습니다

코드 예-작동중인 Winston 로거

//your centralized logger object
var logger = new winston.Logger({
 level: 'info',
 transports: [
 new (winston.transports.Console)(),
 new (winston.transports.File)({ filename: 'somefile.log' })
 ]
 });

//custom code somewhere using the logger
logger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });

블로그 인용문 : “로거의 몇 가지 요구 사항을 식별 할 수 있습니다.”(블로그 strongblog에서)

… 로거의 몇 가지 요구 사항을 식별 할 수 있습니다. 1. 각 로그 라인에 타임 스탬프가 있습니다. 이것은 매우 자명 한 것으로 각 로그 항목이 언제 발생했는지 알 수 있어야합니다. 2. 로깅 형식은 기계는 물론 사람도 쉽게 소화 할 수 있어야합니다. 3. 여러 구성 가능한 대상 스트림을 허용합니다. 예를 들어, 추적 로그를 하나의 파일에 쓰는 중일 수 있지만 오류가 발생하면 같은 파일에 쓴 다음 오류 파일에 쓰고 동시에 전자 메일을 보냅니다.


Number8 : APM 제품을 사용한 오류 및 다운 타임 발견

TL; DR : 모니터링 및 성능 제품 (일명 APM)은 코드베이스 또는 API를 사전에 측정하여 누락 된 오류, 충돌 및 느린 부분을 자동으로 강조 표시 할 수 있습니다.

그렇지 않으면 : API 성능 및 다운 타임을 측정하는 데 많은 노력을 기울일 수 있습니다 . 실제 시나리오에서 가장 느린 코드 부분과 이것이 UX에 어떤 영향을 미치는지 알지 못할 것입니다.

블로그 인용 : “APM 제품 세그먼트”(블로그에서 Yoni Goldberg)

“… APM 제품은 3 가지 주요 부문으로 구성됩니다. 1. 웹 사이트 또는 API 모니터링 – HTTP 요청을 통해 가동 시간 및 성능을 지속적으로 모니터링하는 외부 서비스입니다. 몇 분 안에 설정할 수 있습니다. Pingdom, Uptime Robot 및 New Relic
2 코드 계측 – 기능이 느린 코드 감지, 예외 통계, 성능 모니터링 등을 위해 애플리케이션 내에 에이전트를 포함해야하는 제품군 : New Relic, App Dynamics
3. 운영 인텔리전스 대시 보드 –이 제품군은 애플리케이션 성능을 쉽게 유지하는 데 도움이되는 메트릭 및 선별 된 컨텐츠로 운영 팀을 용이하게하는 데 중점을 둡니다. 여기에는 일반적으로 여러 정보 소스 (응용 프로그램 로그, DB 로그, 서버 로그 등)와 선행 대시 보드 디자인 작업이 집계됩니다. 다음은 선정 된 경쟁자입니다. Datadog, Splunk “


위의 단축 버전입니다- 더 많은 모범 사례 및 예제를 참조하십시오.


답변

잡히지 않은 예외를 잡을 수 있지만 사용이 제한적입니다. http://debuggable.com/posts/node-js-dealing-with-uncaught-exceptions 참조 : 4c933d54-1428-443c-928d-4e1ecbdd56cb

monit, forever또는 upstart이 충돌 할 때 노드 프로세스를 다시 시작하는 데 사용할 수 있습니다. 정상적으로 종료하는 것이 가장 좋습니다 (예 : 잡히지 않은 예외 처리기에 모든 인 메모리 데이터 저장).


답변

nodejs 도메인nodejs 에서 오류를 처리하는 가장 최신 방법입니다. 도메인은 전통적으로 발생 된 객체뿐만 아니라 오류 / 기타 이벤트를 모두 캡처 할 수 있습니다. 도메인은 인터셉트 메소드를 통해 첫 번째 인수로 전달 된 오류로 콜백을 처리하는 기능도 제공합니다.

일반적인 try / catch 스타일 오류 처리와 마찬가지로 일반적으로 오류가 발생할 때 오류를 발생시키고 오류를 격리하려는 영역을 차단하여 나머지 코드에 영향을 미치지 않도록하는 것이 가장 좋습니다. 이러한 영역을 “차단”하는 방법은 격리 된 코드 블록으로 함수를 사용하여 domain.run을 호출하는 것입니다.

동기 코드에서는 위와 같이 충분합니다. 오류가 발생하면 오류가 발생하거나 오류를 잡아서 처리하여 되돌려 야 할 데이터를 되돌립니다.

try {
  //something
} catch(e) {
  // handle data reversion
  // probably log too
}

비동기 콜백에서 오류가 발생하면 데이터 롤백 (공유 상태, 데이터베이스와 같은 외부 데이터 등)을 완전히 처리 할 수 ​​있어야합니다. 또는 예외가 발생했음을 나타내는 무언가를 설정해야합니다. 해당 플래그에 관심이있는 경우 콜백이 완료 될 때까지 기다려야합니다.

var err = null;
var d = require('domain').create();
d.on('error', function(e) {
  err = e;
  // any additional error handling
}
d.run(function() { Fiber(function() {
  // do stuff
  var future = somethingAsynchronous();
  // more stuff

  future.wait(); // here we care about the error
  if(err != null) {
    // handle data reversion
    // probably log too
  }

})});

위의 코드 중 일부는 추악하지만, 예를 들어 더 예쁘게 만들기 위해 패턴을 만들 수 있습니다.

var specialDomain = specialDomain(function() {
  // do stuff
  var future = somethingAsynchronous();
  // more stuff

  future.wait(); // here we care about the error
  if(specialDomain.error()) {
    // handle data reversion
    // probably log too
  }
}, function() { // "catch"
  // any additional error handling
});

업데이트 (2013-09) :

위에서, 섬유 의미론 을 내포하는 미래를 사용하여 미래의 인라인을 기다릴 수 있습니다. 실제로 모든 것을 위해 전통적인 try-catch 블록을 사용할 수 있습니다 . 그러나 항상 이렇게 할 수는 없습니다 (예 : 브라우저에서).

섬유 시맨틱이 필요하지 않은 선물도 있습니다 (일반 브라우저 브라우저 JavaScript에서 작동). 이것을 선물, 약속 또는 이연이라고 부를 수 있습니다 (여기서는 선물을 참조하겠습니다). 평범한 자바 스크립트 선물 라이브러리를 사용하면 선물간에 오류를 전파 할 수 있습니다. 이 라이브러리 중 일부만이 미래에 올바르게 처리 될 수 있으므로주의하십시오.

예를 들면 :

returnsAFuture().then(function() {
  console.log('1')
  return doSomething() // also returns a future

}).then(function() {
  console.log('2')
  throw Error("oops an error was thrown")

}).then(function() {
  console.log('3')

}).catch(function(exception) {
  console.log('handler')
  // handle the exception
}).done()

이것은 조각이 비동기 적이지만 일반적인 try-catch를 모방합니다. 다음과 같이 인쇄됩니다.

1
2
handler

해당 흐름을 방해하는 예외가 발생했기 때문에 ‘3’을 인쇄하지 않습니다.

블루 버드 약속을 살펴보십시오.

throw 된 예외를 올바르게 처리하는 라이브러리 이외의 많은 라이브러리를 찾지 못했습니다. 예를 들어, jQuery는 연기하지 않습니다. “실패”핸들러는 ‘then’핸들러에서 예외를 얻지 못합니다.


답변

최근에 http://snmaynard.com/2012/12/21/node-error-handling/에 썼습니다 . 버전 0.8에서 노드의 새로운 기능은 도메인이며 모든 형태의 오류 처리를 하나의 더 쉬운 관리 양식으로 결합 할 수 있습니다. 내 게시물에서 그들에 대해 읽을 수 있습니다.

또한 Bugsnag 와 같은 것을 사용 하여 포착되지 않은 예외를 추적하고 이메일, 대화방을 통해 알림을 받거나 포착되지 않은 예외에 대한 티켓을 만들 수 있습니다 (Bugsnag의 공동 설립자입니다).


답변

Step.js 라이브러리 를 추가하고 싶습니다. 는 예외를 항상 다음 단계 함수로 전달하여 예외를 처리하는 데 도움이 . 따라서 이전 단계에서 오류를 확인하는 기능을 마지막 단계로 사용할 수 있습니다. 이 접근 방식은 오류 처리를 크게 단순화 할 수 있습니다.

아래는 github 페이지에서 인용 한 것입니다.

발생 된 예외는 포착되어 다음 함수에 대한 첫 번째 인수로 전달됩니다. 콜백 함수를 기본 함수에 인라인하지 않으면 예외가 발생하지 않습니다. 한 번의 포착되지 않은 예외로 인해 전체 서버가 다운 될 수 있으므로 JS 서버는 장기 실행 노드에 매우 중요합니다.

또한 단계를 사용하여 스크립트 실행을 제어하여 마지막 단계와 같이 정리 섹션을 가질 수 있습니다. 예를 들어 노드에 빌드 스크립트를 작성하고 작성하는 데 걸린 시간을보고하려는 경우 마지막 단계는 마지막 콜백을 발굴하지 않고 수행 할 수 있습니다.


답변

try-catch를 사용하는 것이 적절한 경우는 forEach 루프를 사용하는 경우입니다. 동기식이지만 동시에 내부 범위에서 return 문을 사용할 수는 없습니다. 대신 try and catch 방식을 사용하여 적절한 범위에서 Error 객체를 반환 할 수 있습니다. 치다:

function processArray() {
    try {
       [1, 2, 3].forEach(function() { throw new Error('exception'); });
    } catch (e) {
       return e;
    }
}

위의 @balupton에서 설명한 접근 방식의 조합입니다.