본문 바로가기

언어/Node.js

[ Node.js ] 비동기 함수에서 발생하는 에러 처리하기

반응형

 

 

Node.js에서 비동기 함수에서 발생하는 에러를 처리하는 것은 안정적인 애플리케이션 개발에 있어서 매우 중요합니다. 에러 처리는 사용자가 에러 상황에 적절히 대응할 수 있도록 하며, 시스템의 안정성과 보안을 유지하는 데 필수적입니다.

JavaScript와 Node.js에서는 비동기 작업을 처리하는 다양한 방법들이 있으며, 각각의 방법에 따라 에러 처리 방식도 다릅니다. 여기서는 콜백, 프로미스(Promise), 그리고 async/await를 사용할 때 발생하는 에러를 처리하는 방법을 설명합니다.

1. 콜백 (Callback)에서의 에러 처리

콜백 패턴에서 에러 처리는 일반적으로 첫 번째 인수로 err 객체를 전달하여 수행됩니다. 에러가 발생하면 이 err 객체가 null이 아니게 되고, 이를 통해 에러를 확인하고 처리할 수 있습니다.

const fs = require('fs');

// 비동기 파일 읽기 (콜백 기반)
fs.readFile('example.txt', 'utf8', (err, data) => {
    if (err) {
        console.error('Failed to read file:', err.message);
        return;
    }
    console.log('File content:', data);
});

여기서 readFile 함수는 에러가 발생하면 err 객체를 첫 번째 인수로 콜백에 전달합니다. 에러가 발생하지 않으면 errnull이 됩니다. 코드는 errnull인지 확인하여 에러를 처리하고, 그렇지 않으면 정상적으로 데이터를 처리합니다.

2. 프로미스 (Promise)에서의 에러 처리

프로미스에서는 then 메서드의 두 번째 인수로 에러를 처리하거나, catch 메서드를 사용하여 에러를 처리할 수 있습니다. 일반적으로 catch 메서드를 사용하여 모든 에러를 한 곳에서 처리하는 것이 좋습니다.

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

// 프로미스 기반의 파일 읽기
fs.readFile('example.txt', 'utf8')
    .then(data => {
        console.log('File content:', data);
    })
    .catch(err => {
        console.error('Failed to read file:', err.message);
    });

catch 블록은 프로미스 체인에서 발생한 모든 에러를 처리합니다. 이렇게 하면 에러가 발생했을 때의 처리 로직을 중앙화할 수 있습니다.

3. async/await에서의 에러 처리

async/await 구문을 사용할 때는 일반적으로 try/catch 블록을 사용하여 에러를 처리합니다. await 키워드는 프로미스를 반환하는 함수의 결과를 기다리기 때문에, await 표현식 내에서 발생한 에러는 try 블록에서 잡아낼 수 있습니다.

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

async function readFileAsync() {
    try {
        const data = await fs.readFile('example.txt', 'utf8');
        console.log('File content:', data);
    } catch (err) {
        console.error('Failed to read file:', err.message);
    }
}

readFileAsync();

이 방법은 동기 코드처럼 보이기 때문에 가독성이 높으며, try/catch 블록을 사용하여 에러를 포착하고 처리할 수 있습니다.

4. EventEmitter에서의 에러 처리

Node.js의 EventEmitter를 사용하는 비동기 작업에서는 error 이벤트를 통해 에러를 처리할 수 있습니다. EventEmitter를 사용하는 모듈은 에러가 발생했을 때 error 이벤트를 방출하고, 이를 리스너에서 처리할 수 있습니다.

const EventEmitter = require('events');

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();

myEmitter.on('error', (err) => {
    console.error('An error occurred:', err.message);
});

// 비동기 작업 중 에러 발생 시
myEmitter.emit('error', new Error('Something went wrong!'));

여기서는 error 이벤트를 듣고 에러를 처리하는 리스너를 등록합니다. emit 메서드를 사용하여 에러가 발생했음을 알립니다.

5. 전역 에러 처리

비동기 함수에서 처리되지 않은 예외나 프로미스에서 처리되지 않은 거부는 애플리케이션 전체에 영향을 미칠 수 있습니다. Node.js에서는 이를 위한 전역 에러 핸들러를 설정할 수 있습니다.

  • Unhandled Rejection: 처리되지 않은 프로미스 거부를 감지할 수 있습니다.
process.on('unhandledRejection', (reason, promise) => {
    console.error('Unhandled Rejection at:', promise, 'reason:', reason);
    // 로깅 후 프로세스를 안전하게 종료하거나 재시작
});
  • Uncaught Exception: 처리되지 않은 예외를 감지할 수 있습니다.
process.on('uncaughtException', (err) => {
    console.error('Uncaught Exception:', err.message);
    // 로깅 후 프로세스를 안전하게 종료하거나 재시작
    process.exit(1); // 비정상 종료
});

이 핸들러들은 주로 긴급한 에러 로깅 및 애플리케이션의 비정상 종료를 방지하는 데 사용됩니다. 하지만 애플리케이션의 모든 부분에서 적절한 에러 처리를 하는 것이 더욱 중요합니다.

6. 요약

Node.js에서 비동기 함수에서 발생하는 에러를 처리하는 방법은 다음과 같습니다:

  1. 콜백: 콜백 함수의 첫 번째 인수로 에러 객체를 전달하여 처리합니다.
  2. 프로미스: catch 메서드를 사용하여 프로미스 체인에서 발생한 에러를 처리합니다.
  3. async/await: try/catch 블록을 사용하여 에러를 포착하고 처리합니다.
  4. EventEmitter: error 이벤트를 방출하고 리스너에서 에러를 처리합니다.
  5. 전역 에러 처리: unhandledRejectionuncaughtException 이벤트를 사용하여 전역적인 에러를 처리합니다.

이러한 방법들을 이해하고 상황에 맞게 적용하면, Node.js 애플리케이션에서의 에러를 효과적으로 관리할 수 있습니다.

반응형