▶ JavaScript Async |
JavaScript Callbacks |
JavaScript Asynchronous |
JavaScript Promises |
JavaScript Async-Await |
JavaScript Promises
JavaScript Promises: 개념과 사용법
- *JavaScript의 프라미스(Promise)**는 비동기 작업을 처리하기 위한 객체로, 성공(fulfilled) 또는 실패(rejected) 상태를 관리하고 그 결과를 비동기적으로 처리할 수 있게 해줍니다. 프라미스는 콜백 함수의 단점인 콜백 헬(Callback Hell) 문제를 해결하며, 가독성과 유지보수성을 향상시킵니다.
이 가이드는 JavaScript에서 프라미스의 개념과 실용적인 사용법을 설명합니다.
1. 프라미스(Promise)란?
- *프라미스(Promise)**는 비동기 작업의 결과를 처리하는 객체입니다. 프라미스는 대기(pending) 상태에서 시작하여, 작업이
완료되면 성공(fulfilled) 또는 실패(rejected) 상태로 변환됩니다. 이후, 성공 시 처리할
작업과 실패 시 처리할 작업을 각각 **
then()
*과 **catch()
*로 정의할 수 있습니다.
1.1. 프라미스의 상태
- 대기(pending): 프라미스가 완료되지 않은 상태.
- 이행(fulfilled): 프라미스가 성공적으로 완료된 상태.
- 거부(rejected): 프라미스가 실패한 상태.
1.2. 프라미스 기본 구조
const myPromise = new Promise((resolve, reject) => {
// 비동기 작업 수행
const success = true; // 작업 성공 여부
if (success) {
resolve('Task completed successfully!');
} else {
reject('Task failed.');
}
});
myPromise
.then((result) => {
console.log(result); // 성공 시 실행
})
.catch((error) => {
console.log(error); // 실패 시 실행
});
resolve()
: 프라미스가 성공했을 때 호출되며, **then()
*에서 처리됩니다.reject()
: 프라미스가 실패했을 때 호출되며, **catch()
*에서 처리됩니다.
2. 프라미스 사용 예시
2.1. 비동기 작업 처리 예시
프라미스는 비동기 작업의 결과를 처리하는 데 자주 사용됩니다. 예를 들어, 서버에서 데이터를 가져오는 작업을 프라미스로 처리할 수 있습니다.
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('Data fetched successfully.');
} else {
reject('Error fetching data.');
}
}, 2000);
});
}
fetchData()
.then((data) => {
console.log(data); // Data fetched successfully. (2초 후 실행)
})
.catch((error) => {
console.log(error); // Error fetching data.
});
fetchData()
함수는 프라미스를 반환하며, 성공 시 **resolve()
*를 호출하고 실패 시 **reject()
*를 호출합니다.- *
then()
*과 **catch()
*를 사용해 각각 성공과 실패를 처리할 수 있습니다.
3. 프라미스 체이닝 (Promise Chaining)
- *프라미스 체이닝(Promise Chaining)**을 사용하면, 여러 비동기 작업을 순차적으로 처리할 수 있습니다. 각
then()
메서드는 다음 프라미스를 반환할 수 있으며, 이를 통해 작업을 연결할 수 있습니다.
3.1. 프라미스 체이닝 예시
function firstTask() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('Task 1 complete');
resolve('Task 1 result');
}, 1000);
});
}
function secondTask(result) {
return new Promise((resolve) => {
setTimeout(() => {
console.log(`Task 2 complete with ${result}`);
resolve('Task 2 result');
}, 1000);
});
}
firstTask()
.then((result) => {
return secondTask(result);
})
.then((result) => {
console.log(`All tasks complete with ${result}`);
});
- *
firstTask()
*와 **secondTask()
*는 각각 프라미스를 반환하며, 비동기 작업이 완료된 후 다음 작업을 수행합니다. - 프라미스 체이닝을 통해 순차적인 비동기 작업을 쉽게 처리할 수 있습니다.
4. Promise.all()
, Promise.race()
4.1. Promise.all()
- *
Promise.all()
*은 여러 프라미스가 **모두 이행(fulfilled)**될 때까지 기다린 후, 그 결과를 배열로 반환합니다. 모든 프라미스가 성공해야지만 **then()
*이 호출됩니다. 하나라도 **실패(rejected)**하면 **catch()
*가 호출됩니다.
const promise1 = new Promise((resolve) => setTimeout(resolve, 1000, 'First'));
const promise2 = new Promise((resolve) => setTimeout(resolve, 2000, 'Second'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 3000, 'Third'));
Promise.all([promise1, promise2, promise3])
.then((results) => {
console.log(results); // ['First', 'Second', 'Third']
})
.catch((error) => {
console.log(error); // 하나라도 실패하면 호출
});
- *
Promise.all()
*은 모든 프라미스가 성공적으로 완료될 때 결과 배열을 반환합니다. - 하나라도 실패하면 **즉시
catch()
*로 넘어갑니다.
4.2. Promise.race()
- *
Promise.race()
*는 가장 먼저 완료된 프라미스의 결과를 반환합니다. 첫 번째로 **이행(fulfilled)**되거나 **거부(rejected)**된 프라미스가 결과로 반환됩니다.
const fastPromise = new Promise((resolve) => setTimeout(resolve, 1000, 'Fast'));
const slowPromise = new Promise((resolve) => setTimeout(resolve, 3000, 'Slow'));
Promise.race([fastPromise, slowPromise])
.then((result) => {
console.log(result); // 'Fast' (가장 빠른 프라미스가 반환됨)
})
.catch((error) => {
console.log(error); // 첫 번째 실패한 프라미스가 있으면 에러 처리
});
- *
Promise.race()
*는 가장 먼저 완료된 프라미스의 결과를 반환하며, 그 결과가 성공이든 실패든 상관없이 가장 빠른 프라미스가 처리됩니다.
5. async/await
를 사용한 프라미스 처리
- *
async/await
*는 프라미스를 더 간결하고 직관적으로 처리할 수 있게 해줍니다. **await
*는 프라미스가 완료될 때까지 기다린 후, 그 결과를 반환받습니다.
5.1. async/await
기본 사용법
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('Data fetched');
}, 2000);
});
}
async function displayData() {
const data = await fetchData();
console.log(data); // 'Data fetched' (2초 후 출력)
}
displayData();
async
키워드를 사용해 비동기 함수를 정의하며, 함수 내에서 **await
*를 사용해 프라미스가 완료될 때까지 기다립니다.- 프라미스 체이닝을 사용하는 것보다 가독성이 훨씬 높아집니다.
5.2. async/await
와 오류 처리
- *
async/await
*에서도try...catch
구문을 사용하여 프라미스의 오류 처리를 할 수 있습니다.
async function displayData() {
try {
const data = await fetchData();
console.log(data);
} catch (error) {
console.log('Error:', error); // 에러 처리
}
}
displayData();
try...catch
구문을 통해 프라미스가 실패했을 때 오류를 처리할 수 있습니다.
6. 프라미스의 장점과 단점
6.1. 장점
- 콜백 헬을 해결하고, 가독성과 **유
지보수성**이 높은 비동기 코드를 작성할 수 있습니다.
- 프라미스 체이닝을 통해 비동기 작업을 순차적으로 처리할 수 있습니다.
- *
async/await
*을 사용하면 더 직관적이고 동기 코드처럼 작성할 수 있습니다.
6.2. 단점
- 오래된 브라우저에서는 **
Promise
*와 **async/await
*가 지원되지 않을 수 있으며, **폴리필(polyfill)**이 필요할 수 있습니다. - 에러 처리가 제대로 이루어지지 않으면 비동기 작업에서 예상치 못한 버그가 발생할 수 있습니다.
요약
- *JavaScript의 프라미스(Promise)**는 비동기 작업을 관리하는 중요한 객체로, 성공 또는 실패를 처리할 수 있습니다. 프라미스는 콜백 함수의 단점을 해결하고, 비동기 작업을 더 쉽게 관리할 수 있게 해줍니다.
- *
Promise
*는 **resolve()
*와 **reject()
*를 통해 성공과 실패를 처리하며, **then()
*과 **catch()
*로 그 결과를 처리합니다. - 프라미스 체이닝을 통해 여러 비동기 작업을 순차적으로 처리할 수 있습니다.
- *
Promise.all()
*과 **Promise.race()
*를 통해 여러 프라미스를 동시에 처리할 수 있습니다. - *
async/await
*를 사용하면 프라미스를 더 직관적이고 간결하게 처리할 수 있으며, 오류 처리도 쉽게 할 수 있습니다.
프라미스는 비동기 프로그래밍에서 중요한 도구이며, 네트워크 요청이나 파일 입출력과 같은 비동기 작업에서 필수적으로 사용됩니다.