Node.js 8의 util.promisify로 콜백 지옥 탈출하기
문제 상황
프로젝트에서 파일 시스템 작업과 외부 API 호출이 중첩되면서 콜백 지옥이 심각해졌다. Promise를 직접 래핑하는 방식으로 해결하고 있었지만, Node.js 8에 추가된 util.promisify를 사용하면 더 간결하게 처리할 수 있다는 것을 알게 되었다.
기존 코드
const fs = require('fs');
fs.readFile('config.json', 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
const config = JSON.parse(data);
fs.writeFile('output.json', JSON.stringify(config), (err) => {
if (err) console.error(err);
});
});
util.promisify 적용
const util = require('util');
const fs = require('fs');
const readFile = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);
async function processConfig() {
try {
const data = await readFile('config.json', 'utf8');
const config = JSON.parse(data);
await writeFile('output.json', JSON.stringify(config));
} catch (err) {
console.error(err);
}
}
processConfig();
커스텀 함수 promisify
레거시 API 중에는 에러-퍼스트 콜백 패턴을 따르지 않는 경우도 있었다. 이런 경우 util.promisify.custom 심볼을 사용해 커스텀 promisify 로직을 구현할 수 있다.
function customAPI(arg, callback) {
// 비표준 콜백 패턴
setTimeout(() => callback(arg * 2), 100);
}
customAPI[util.promisify.custom] = (arg) => {
return new Promise((resolve) => {
customAPI(arg, resolve);
});
};
const promisifiedAPI = util.promisify(customAPI);
결과
프로젝트 전반에 걸쳐 콜백 기반 코드를 async/await으로 전환했다. 코드 가독성이 크게 개선되었고, 에러 핸들링도 try-catch로 통일할 수 있었다. Node.js 8 업그레이드의 가장 큰 수확이었다.