exception-handling 현상 - Node.js 모범 사례 예외 처리




에러처리 단점 (9)

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

  • process.on('uncaughtException') 만이이를 보호하는 효과적인 방법입니까?
  • process.on('uncaughtException') 은 비동기 프로세스 실행 중에 처리되지 않은 예외를 catch합니까?
  • 잡히지 않은 예외의 경우에 활용할 수있는 이미 구축 된 모듈 (예 : 전자 메일 보내기 또는 파일에 쓰기)이 있습니까?

node.js에서 캐치되지 않은 예외를 처리하는 일반적인 최선의 방법을 보여줄 포인터 / 아티클에 감사드립니다.


Answers

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

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



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

다음은 github 페이지의 견적입니다.

throw 된 모든 예외는 catch되어 첫 번째 인수로 다음 함수로 전달됩니다. 콜백 함수를 인라인하지 않고 main 함수를 인라인하면, 잡히지 않은 예외가 발생하지 않습니다. 잡히지 않은 단일 예외로 인해 전체 서버가 다운 될 수 있기 때문에 장시간 실행되는 node.JS 서버에서는 매우 중요합니다.

또한 Step을 사용하여 스크립트 실행을 제어하여 섹션 정리 섹션을 마지막 단계로 사용할 수 있습니다. 예를 들어 Node에 빌드 스크립트를 작성하고 작성하는 데 걸리는 시간을보고 싶다면 마지막 단계에서 마지막 콜백을 파싱하지 않고 할 수 있습니다.


잡기 오류는 여기에서 매우 잘 논의되어 왔지만, 어딘가에 오류를 기록해서 기억하고 볼 수 있도록하는 것이 중요합니다.

Bunyan은 NodeJS에 대한 널리 사용되는 로깅 프레임 워크입니다. console.log를 피할 수만 있다면 로컬 디버깅에 유용하게 사용할 수있는 다양한 출력 위치를 작성해야합니다. 도메인의 오류 처리기에서 로그 파일에 오류가 발생할 수 있습니다.

var log = bunyan.createLogger({
  name: 'myapp',
  streams: [
    {
      level: 'error',
      path: '/var/tmp/myapp-error.log'  // log ERROR to this file
    }
  ]
});

검사 할 오류 및 / 또는 서버가 많으면 시간이 오래 걸릴 수 있으므로 Raygun (면책 조항, Raygun에서 작업)과 같은 도구를 살펴보고 오류를 함께 그룹화하거나 함께 사용하는 것이 좋습니다. Raygun을 도구로 사용하기로 결정했다면 설정하기가 매우 쉽습니다.

var raygunClient = new raygun.Client().init({ apiKey: 'your API key' });
raygunClient.send(theError);

PM2와 같은 도구를 사용하거나 영원히 교차하면 앱이 충돌하고 로그 아웃 할 수 있어야하며 중요한 문제없이 재부팅 할 수 있어야합니다.


이 게시물을 읽은 후 얼마 전 API / 함수 수준에서 예외 처리를 위해 도메인을 사용하는 것이 안전한지 궁금했습니다. 필자가 쓴 각각의 비동기 함수에서 예외 처리 코드를 단순화하기 위해 그것들을 사용하고 싶었다. 내 관심사는 각 기능에 대해 새로운 도메인을 사용하면 상당한 오버 헤드가 발생한다는 것입니다. 저의 숙제는 최소한의 오버 헤드가 있으며 성능은 실제로 상황에 따라 잡는 것보다 도메인에서 더 낫다는 것을 나타냅니다.

http://www.lighthouselogic.com/#/using-a-new-domain-for-each-async-function-in-node/


다음은 선택한 블로그 게시물의 코드 예제 및 따옴표를 비롯하여이 주제에 대한 다양한 소스의 요약 및 큐 레이션입니다. 모범 사례의 전체 목록은 여기에서 찾을 수 있습니다.

Node.JS 오류 처리 모범 사례

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

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

그렇지 않으면 : Node.JS 콜백 스타일, 함수 (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 : 내장 된 Error 객체 만 사용하십시오.

TL : 오류를 문자열이나 사용자 정의 유형으로 던지는 코드를 보는 것이 일반적입니다 . 이는 오류 처리 논리와 모듈 간의 상호 운용성을 복잡하게합니다. 약속을 거부하든, 예외를 던지거나 오류를 발생시킵니다. 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?");

블로그 인용구 : "문자열은 오류가 아닙니다" (블로그 "devthought"에서 키워드 "Node.JS 오류 개체"에 대해 6 위)

"... 오류 대신 문자열을 전달하면 모듈 간 상호 운용성이 저하되며 instanceof 오류 검사를 수행하고 있거나 오류에 대해 더 알고 싶어하는 API와 계약이 끊어집니다 . 오류 객체는 메시지를 생성자에 전달하는 것 외에 현대 자바 스크립트 엔진에서 흥미로운 속성 "

Number3 : 작동 및 프로그래머 오류 구분

TL : 운영 오류 (예 : 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 미들웨어, cron 작업, 단위 테스트)가 호출하는 전용 집중 개체에 캡슐화되어야합니다.

그렇지 않으면 : 한 곳에서 오류를 처리하지 않으면 코드가 중복되고 부적절하게 처리되는 오류가 발생할 수 있습니다

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

//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 오류 처리"키워드에 대해 1 위를 차지함)

"... 스택의 여러 레벨에서 같은 오류를 처리하게 될 수도 있습니다. 이것은 하위 레벨이 호출자에게 오류를 전파하고 호출자에게 오류를 전파하는 것을 제외하고는 아무 것도 할 수없는 경우에 발생합니다. 최상위 호출자 만 적절한 응답이 무엇인지, 작업을 다시 시도할지, 사용자에게 오류를보고할지 또는 다른 어떤 것인지를 알 수 있습니다. 그러나 모든 오류를 단일 최상위 수준에보고해야한다는 것을 의미하지는 않습니다 콜백은 그 콜백 자체가 어떤 컨텍스트에서 에러가 발생했는지 알 수 없기 때문에 "

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

TL : DR : API 호출자가 어떤 오류가 발생했는지 알 수 있도록하여 충돌없이 신중하게 처리 할 수 ​​있도록합니다. 이것은 일반적으로 Swagger와 같은 REST API 문서 프레임 워크로 수행됩니다.

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

블로그 인용문 : "발신자에게 어떤 오류가 발생할 수 있는지 알려줘야합니다."(Joyent 블로그에서 "Node.JS logging"키워드에 대해 1 위를 차지했습니다)

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

넘버 6 : 낯선 사람이 마을에 올 때 공정을 정상적으로 중단하십시오.

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

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

코드 예제 - 크래시 할 것인지 결정

//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 logger in action

//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 : 모니터링 및 성능 제품 (일명 APM)은 코드베이스 또는 API를 사전에 측정하여 누락 된 오류, 충돌 및 느린 부분을 자동으로 강조 표시합니다.

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

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

"... APM 제품은 3 가지 주요 부분으로 구성됩니다 : 1. 웹 사이트 또는 API 모니터링 - HTTP 요청을 통해 가동 시간과 성능을 지속적으로 모니터하는 외부 서비스 몇 분 안에 설정 가능 다음은 Pingdom, 가동 시간 로봇 및 New Relic 2 코드 계측 - 느린 코드 감지, 예외 통계, 성능 모니터링 등의 혜택을 누리기 위해 애플리케이션 내에 에이전트를 내장해야하는 제품군 - New Relic, App Dynamics 3. Operational Intelligence Dashboard - 이러한 라인 제품의 여러 가지 정보 (응용 프로그램 로그, DB 로그, 서버 로그 등)를 집계하고 선행 대시 보드 디자인을 포함하는 응용 프로그램 성능을 쉽게 유지하는 데 도움이되는 메트릭 및 큐레이팅 된 콘텐츠로 운영 팀을 지원하는 데 중점을 둡니다. 다음은 몇 가지 경쟁자입니다 : Datadog, Splunk "

위의 내용은 단축 된 버전입니다 - 모범 사례와 예제에 대한 자세한 내용은 여기를 참조하십시오.


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

일반적인 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 블록을 사용할 수 있도록 해줍니다 - 나는 이것이 최선의 방법이라고 생각합니다. 그러나, 당신은 항상 이것을 할 수 없다 (예 : 브라우저에서) ...

파이버 의미론을 필요로하지 않는 미래도 있습니다 (보통의 브라우저 자바 스크립트에서 작동합니다). 이것들은 선물, 약속 또는 연기라고 할 수 있습니다 (여기에서 나는 미래에 대해서만 언급 할 것입니다). Plain-old-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'이 인쇄되지 않습니다.

블루 버드 약속에 대해 살펴보십시오.

던져진 예외를 적절히 처리하는 다른 라이브러리가 많이 있습니다. 예를 들어, jQuery는 지연됩니다. "실패한"핸들러는 예외 처리기를 던지지 않을 것입니다. 제 생각에는 처리기입니다.


업데이트 : Joyent는 이제이 답변 에서 언급 한 가이드를 보유 하고 있습니다 . 다음 정보는 요약입니다.

안전하게 "던지는"오류

이상 적으로 우리는 가능한 한 많이 잡히지 않는 오류를 피하고 싶습니다. 문자 그대로 오류를 던지는 대신 코드 구조에 따라 다음 방법 중 하나를 사용하여 오류를 안전하게 "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 입니다. 오류가 발생하면 오류가 발생하고 오류가 발생하지 않으면 errnull 입니다. 다른 인수는 err 인수 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)
        }
    })
    
  • 오류가 발생한 곳에서 오류가 발생할 수있는 eventful 코드의 경우 대신 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) try catch 잡기 실행을 원하지 않는 경우를 방지하는 것이 가장 좋습니다. 자바 스크립트의 비동기 이벤트 - 머신 스타일 대신에 적절한 스레딩을 허용하는 언어에서는 이것이 문제가되지 않습니다.

  • 마지막으로 도메인이나 try 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
    

IntelliJ 는 Node.js를 멋지게 사용합니다.

또한 IntelliJ는 '코드 지원'을 잘 지원합니다.







node.js exception-handling serverside-javascript