Node.js 8의 util.promisify로 콜백 지옥 탈출하기

문제 상황

레거시 API 서버를 유지보수하면서 콜백 중첩이 심각한 코드를 마주쳤다. fs, crypto 등 Node.js 기본 모듈을 사용하는 부분이 특히 심했다.

fs.readFile('config.json', 'utf8', (err, data) => {
  if (err) return callback(err);
  crypto.randomBytes(16, (err, buffer) => {
    if (err) return callback(err);
    // 계속 중첩...
  });
});

util.promisify 도입

Node.js 8.0.0부터 util.promisify가 정식 지원된다. 콜백 스타일 함수를 Promise로 변환해주는 유틸이다.

const util = require('util');
const fs = require('fs');
const crypto = require('crypto');

const readFile = util.promisify(fs.readFile);
const randomBytes = util.promisify(crypto.randomBytes);

async function loadConfig() {
  try {
    const data = await readFile('config.json', 'utf8');
    const buffer = await randomBytes(16);
    return { config: JSON.parse(data), token: buffer.toString('hex') };
  } catch (err) {
    console.error('Error:', err);
    throw err;
  }
}

적용 결과

  • 콜백 중첩 5단계 → async/await 플랫 구조로 변경
  • 에러 핸들링이 try-catch로 통일되어 관리 용이
  • 테스트 코드 작성 시 Promise 체이닝 활용 가능

주의사항

promisify는 Node.js 콜백 컨벤션(error-first callback)을 따르는 함수에만 사용 가능하다. 커스텀 콜백 형태는 직접 Promise wrapper를 작성해야 한다.

당분간은 기존 코드와 혼용하면서 점진적으로 마이그레이션할 예정이다.