웹 개발에서 비동기 작업은 매우 흔하다고 한다
비동기 작업?
특정 코드가 끝날때 까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 것을 의미한다
즉 병렬적으로 처리가 가능한 작업.
콜백 함수??
- 콜백이란 다른 함수(A)의 전달인자(argument)로 넘겨주는 함수(B)를 말한다.
- 매개변수를 넘겨 받은 함수(A)는 callback 함수(B)를 필요에 따라 즉시 실행(synchronously) 할 수도 있고, 아니면 나중에 (asynchronously) 실행할 수도 있다.
이제 콜백 지옥을 봐보자
getData(function(data) {
processData(data, function(processedData) {
renderData(processedData, function() {
console.log('Done!');
});
});
});
- getData함수를 호출하고, 익명 함수를 콜백으로 전달한다
- getData가 작업을 완료하면 첫 번째 콜백 함수를 호출하고, 결과 data를 전달한다
- 콜백 함수 내부에서 processData를 호출하고 다시 익명함수를 콜백으로 전달한다.
- processData가 작업을 완료하면 두 번 째 콜백 함수를 호출하고, 결과 processedData를 전달한다
- 콜백 함수 내부에서 renderData를 호출하고, 또 다시 익명 함수를 콜백으로 전달한다
- renderData가 작업을 완료하면 세 번째 콜백 함수를 호출하고, 이 함수는 console.log("Done!")을 실행한다
위와 같은 코드를 콜백 지옥이라고 부른다
가독성이 떨어지고 오류 처리가 복잡해 질 수 있다
// Promise 체인 사용
getData()
.then(data => processData(data))
.then(processedData => renderData(processedData))
.then(() => console.log('Done!'))
.catch(error => console.error('Error:', error));
// 또는 async/await 사용
async function handleData() {
try {
const data = await getData();
const processedData = await processData(data);
await renderData(processedData);
console.log('Done!');
} catch (error) {
console.error('Error:', error);
}
}
handleData();
위와 같이 Promise를 사용하거나 async / await을 사용하면 코드가 더 선형적이고 읽기 쉬워진다.
물론 여기서 Promise 체인을 사용하려면 각 함수가 Promise객체를 반환해야 한다.
Promise 객체란?
- JavaScript에서 비동기 작업의 최종 완료(또는 실패)와 그 결과값을 나타내는 객체이다. 쉽게 말해, Promise는 "약속"과 같은 개념으로, "나중에 완료될 작업의 결과를 약속" 한다
- 작업의 결과가 promise 객체에 저장됩니다. promise 객체를 보면 작업이 성공했는지, 실패했는지 알 수 있다.
async / await
async는 함수의 앞에 붙어서 해당 함수가 비동기 함수임을 나타낸다.
await는 비동기 함수의 실행 결과를 기다리는 키워드이다
마지막으로 좀 익명 함수와 콜백이 이해가 안되서 간단한 예제를 만들어 보았으니 보면서 이해해보자
// 간단한 콜백 로그 예제
getData(function (data) {
console.log('1. getData의 콜백 실행');
processData(data, function (processedData) {
console.log('2. processData의 콜백 실행');
console.log(' 전달받은 데이터:', processedData);
renderData(processedData, function () {
console.log('3. renderData의 콜백 실행');
console.log('4. 모든 과정 완료: Done!');
});
});
});
function getData(callback) {
console.log('getData 함수 시작');
// 데이터 없이 바로 콜백 호출
callback('초기 데이터');
}
function processData(data, callback) {
console.log('processData 함수 시작');
console.log('받은 데이터:', data);
// 데이터 처리 후 바로 콜백 호출
callback('처리된 데이터');
}
function renderData(processedData, callback) {
console.log('renderData 함수 시작');
console.log('렌더링할 데이터:', processedData);
// 렌더링 후 바로 콜백 호출
callback();
}
출력 결과
getData 함수 시작
1. getData의 콜백 실행
processData 함수 시작
받은 데이터: 초기 데이터
2. processData의 콜백 실행
전달받은 데이터: 처리된 데이터
renderData 함수 시작
렌더링할 데이터: 처리된 데이터
3. renderData의 콜백 실행
4. 모든 과정 완료: Done!