본문 바로가기

Programming/Node.js

4. Node 기능 살펴보기 (11) - 예외 처리하기 [2]

node js logo image

 

 

 

 

앞선 아티클에서 throw를 사용해 try / catch 문으로 에러를 잡는 연습을 해보았습니다. 반대로, 이번에는 노드에서 자체적으로 잡아주는 에러 예제를 살펴보도록 하겠습니다. 

 

 

const fs = require('fs');

setInterval( () => {
    fs.unlink('./abcdefg.js', (err) => {
        if (err) {
            console.error(err);
        }
    });
}, 1000);


/* 출력
[Error: ENOENT: no such file or directory, unlink 'D:\Study\Javascript\abcdefg.js'] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'unlink',
  path: 'D:\\Study\\Javascript\\abcdefg.js'
}
[Error: ENOENT: no such file or directory, unlink 'D:\Study\Javascript\abcdefg.js'] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'unlink',
  path: 'D:\\Study\\Javascript\\abcdefg.js'
}
[Error: ENOENT: no such file or directory, unlink 'D:\Study\Javascript\abcdefg.js'] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'unlink',
  path: 'D:\\Study\\Javascript\\abcdefg.js'
}
....
// 반복
*/

 

 

 

위의 예제에서는 존재하지 않는 파일을 지우려고 시도하는데, 에러가 발생해도 내장 모듈의 에러는 실행 중인 프로세스 자체를 중단시키지는 않습니다. 에러 로그를 기록하고, 나중에 원인을 찾아 수정하는 방식입니다. 

 

참고로 앞의 버퍼 / 스트림 아티클에서는 비슷한 방식의 예제에서 throw를 사용했습니다. throw를 사용할 경우에는 노드의 동작이 멈춰버립니다. 이 경우, 반드시 throw와 함께 try / catch 처리를 해주어야만 합니다.

 

 

 


 

 

 

 

비슷한 메서드인데, 프로미스에서의 에러도 살펴보겠습니다. 노드 16부터 프로미스에서 발생하는 에러는 반드시 catch 해야 합니다(catch 하지 않으면 노드 프로세스 자체가 종료됩니다).

 

const fs = require('fs').promises;

setInterval( () => {
    fs.unlink('./abcdefg.js').catch(console.error);
}, 1000);

/* 출력
[Error: ENOENT: no such file or directory, unlink 'D:\Study\Javascript\abcdefg.js'] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'unlink',
  path: 'D:\\Study\\Javascript\\abcdefg.js'
}
[Error: ENOENT: no such file or directory, unlink 'D:\Study\Javascript\abcdefg.js'] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'unlink',
  path: 'D:\\Study\\Javascript\\abcdefg.js'
}

//반복
*/

 

 

 

 


 

 

 

따로 정의되지 않은, 말 그대로 "예상치 못한 에러"를 처리하는 방법도 살펴보겠습니다. 여기서 예상치 못한 에러가 발생하는 이벤트를 'uncaughtException'으로 정의합니다. 

 

 

process.on('uncaughtException', (err) => {
    console.error('예상하지 못한 에러의 발생!', err);
});

setInterval( () => {
    throw new Error("*처음보는 서버 오류*");
}, 1000);

setTimeout( () => {
    console.log('실행은 계속된다');
});

/* 출력
실행은 계속된다
예상하지 못한 에러의 발생! Error: *처음보는 서버 오류*
    at Timeout._onTimeout (D:\Study\Javascript\example.js:6:11)
    at listOnTimeout (node:internal/timers:573:17)
    at process.processTimers (node:internal/timers:514:7)
예상하지 못한 에러의 발생! Error: *처음보는 서버 오류*
    at Timeout._onTimeout (D:\Study\Javascript\example.js:6:11)
    at listOnTimeout (node:internal/timers:573:17)
    at process.processTimers (node:internal/timers:514:7)
예상하지 못한 에러의 발생! Error: *처음보는 서버 오류*
    at Timeout._onTimeout (D:\Study\Javascript\example.js:6:11)
    at listOnTimeout (node:internal/timers:573:17)
    at process.processTimers (node:internal/timers:514:7)

// 반복
*/

 

위에서 실행한 결과를 보면, setTimeout( )은 그래도 정상 실행이 되고, 서버오류가 기록됩니다. uncaughtException 이벤트 리스너를 통해서 프로세스가 유지되는 것이죠. 

 

그럼 모든 에러를 이 uncaughtException 이벤트 리스너로 처리할 수 있을까요? 공식적으로 이 리스너는 이 이벤트 발생 후 다음 동작을 100% 보장하지 못합니다. 그러므로, 이는 단순 에러 기록 용도로 사용하고 - 기록 이후에는 process.exit( )로 프로세스를 종료하는 것이 좋습니다.