비동기 작업을 보다 효율적으로 관리하는 데 필수적인 JavaScript의 Promise는 최신 버전에서도 다양한 개선을 통해 주니어 개발자들이 쉽게 비동기 작업을 다룰 수 있도록 발전하고 있습니다. 이번 글에서는 Promise의 핵심 기능을 최신 자료에 기반해 정리하고, 자주 쓰이는 메서드들을 설명해 보겠습니다.
Promise는 자바스크립트에서 비동기 작업의 상태를 관리하는 객체로, 비동기 작업이 완료되거나 실패했을 때 이를 처리하는 방법을 미리 정의할 수 있습니다. resolve 또는 reject가 호출될 때, 해당 Promise의 상태는 fulfilled 혹은 _rejected_로 변경됩니다. 이를 통해 코드를 더욱 간결하게 작성하고, 비동기 작업이 순차적으로 실행될 수 있도록 도와줍니다.
Promise.all()
Promise.all()
은 여러 비동기 작업을 병렬로 실행하고, 모든 작업이 성공했을 때 그 결과를 배열로 반환합니다. 단, 작업 중 하나라도 실패하면 전체가 실패로 처리됩니다.
const promise1 = Promise.resolve(5);
const promise2 = Promise.resolve(33);
const promise3 = new Promise((resolve) => setTimeout(resolve, 2000, '완료!'));
Promise.all([promise1, promise2, promise3])
.then((results) => console.log(results)); // [5, 33, "완료!"]
이 메서드는 다수의 작업을 동시에 실행할 때 유용하지만, 하나라도 실패하면 전체가 실패로 처리된다는 점을 유의해야 합니다.
Promise.allSettled()
Promise.allSettled()
는 Promise.all()
과 비슷하지만, 모든 Promise가 완료될 때까지 기다리며 성공 여부에 관계없이 결과를 반환합니다. 이 경우 각 작업의 상태와 결과를 모두 알 수 있습니다.
const promise1 = Promise.resolve(9);
const promise2 = new Promise((_, reject) => setTimeout(reject, 4000, '에러 발생!'));
Promise.allSettled([promise1, promise2])
.then((results) => console.log(results));
// [{ status: "fulfilled", value: 9 }, { status: "rejected", reason: "에러 발생!" }]
실패한 작업도 함께 기록하기 때문에, 여러 작업의 결과를 한 번에 처리하는 상황에 적합합니다
Promise.any()
Promise.any()
는 여러 Promise 중 가장 먼저 성공한 하나만 반환하며, 나머지는 무시합니다. 이는 다수의 작업 중 하나만 성공하면 충분한 경우에 유용합니다. 단, 모든 작업이 실패하면 AggregateError라는 특별한 에러가 발생합니다.
const promise1 = Promise.reject(0);
const promise2 = new Promise((resolve) => setTimeout(resolve, 2000, '2초 후 성공!'));
Promise.any([promise1, promise2])
.then((result) => console.log(result)) // "2초 후 성공!"
.catch((error) => console.log(error.errors)); // AggregateError
이 메서드는 특정 작업이 먼저 완료되는지 확인해야 할 때 유용하며, 최초 성공한 Promise의 값만 반환하는 것이 특징입니다
Promise.race()
Promise.race()
는 가장 먼저 완료된 Promise의 결과를 반환합니다. 결과가 성공이든 실패이든 가장 빠르게 완료된 작업이 반환됩니다.
const promise1 = new Promise((resolve) => setTimeout(resolve, 3000, '첫 번째 성공'));
const promise2 = new Promise((resolve) => setTimeout(resolve, 1000, '두 번째 성공'));
Promise.race([promise1, promise2])
.then((result) => console.log(result)); // "두 번째 성공"
이 메서드는 경쟁 상황에서 가장 빠르게 처리된 작업의 결과를 활용해야 할 때 유용합니다
비동기 작업을 효율적으로 관리하는 자바스크립트의 Promise는 개발자가 비동기 코드의 복잡성을 줄이고, 더욱 직관적인 코드 작성을 가능하게 합니다. Promise.all()
, Promise.allSettled()
, Promise.any()
, Promise.race()
와 같은 다양한 메서드를 활용하여 다양한 상황에서 비동기 작업을 최적화할 수 있습니다.
Promise.all()
과 Promise.allSettled()
를 적절히 활용해 보세요.Promise.any()
또는 Promise.race()
를 사용해 보세요.아래는 복잡한 비동기 작업을 다루는 자바스크립트 Promise 예제입니다. 코드 내부에 각 메서드의 기능과 동작 원리에 대한 설명이 주석으로 기재되어 있습니다.
// 여러 비동기 작업을 복합적으로 처리하는 예제
// Promise 객체 3개를 생성합니다.
// 각 작업은 비동기적으로 실행되며, 일정 시간이 지난 후에 완료됩니다.
const task1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Task 1 완료');
resolve('Task 1 결과');
}, 3000); // 3초 후에 완료
});
const task2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Task 2 실패');
reject('Task 2 실패'); // 작업 2는 실패합니다.
}, 2000); // 2초 후에 실패
});
const task3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Task 3 완료');
resolve('Task 3 결과');
}, 4000); // 4초 후에 완료
});
// 1. Promise.all() 사용 예제
// 모든 작업이 성공했을 때만 결과를 반환합니다.
// 하나라도 실패하면 전체가 실패로 처리됩니다.
Promise.all([task1, task2, task3])
.then(results => {
console.log('Promise.all 성공:', results);
})
.catch(error => {
console.log('Promise.all 실패:', error);
});
// task2가 실패하므로 Promise.all은 실패 처리됩니다.
// 2. Promise.allSettled() 사용 예제
// 각 작업의 성공 여부와 상관없이 모든 작업이 완료되면 결과를 반환합니다.
// 각각의 결과는 { status: 'fulfilled' or 'rejected', value or reason } 형태로 반환됩니다.
Promise.allSettled([task1, task2, task3])
.then(results => {
console.log('Promise.allSettled 결과:');
results.forEach((result, index) => {
console.log(`Task ${index + 1}:`, result);
});
});
// 모든 작업의 상태를 알 수 있으므로, 실패한 작업과 성공한 작업을 구분할 수 있습니다.
// 3. Promise.any() 사용 예제
// 가장 먼저 성공한 작업의 결과만 반환합니다.
// 만약 모든 작업이 실패하면 AggregateError가 발생합니다.
Promise.any([task1, task2, task3])
.then(result => {
console.log('Promise.any 성공:', result);
})
.catch(error => {
console.log('Promise.any 실패:', error.errors); // 실패한 이유들을 출력합니다.
});
// task1이 task2보다 늦게 완료되므로 task1의 결과를 반환합니다.
// 4. Promise.race() 사용 예제
// 가장 빨리 완료된 작업의 결과를 반환합니다. 성공이든 실패든 가장 먼저 완료된 작업의 결과가 반환됩니다.
Promise.race([task1, task2, task3])
.then(result => {
console.log('Promise.race 결과:', result);
})
.catch(error => {
console.log('Promise.race 실패:', error);
});
// task2가 가장 빨리 실패하므로 실패 결과가 출력됩니다.
task2
가 실패하기 때문에 Promise.all
은 실패로 처리됩니다.AggregateError
를 발생시킵니다. 이 예제에서는 task1
이 성공하여 그 결과가 반환됩니다.task2
가 가장 빨리 실패하여 그 결과가 반환됩니다.
이 예제는 다양한 상황에서 Promise를 어떻게 활용할 수 있는지를 보여줍니다. 복잡한 비동기 작업에서 Promise를 효과적으로 관리하는 방법을 이해하는 데 도움이 됩니다.
아래는 POST 메서드를 사용하고 파라미터를 전달하는 고급 예제입니다. 여러 개의 API 요청을 동시에 처리하고, 각 요청에 대해 POST 방식으로 데이터를 전송하며, 다양한 상황에 맞게 Promise.all(), Promise.allSettled(), Promise.any(), Promise.race()를 활용하는 방법을 보여줍니다.
아래는 주어진 자바스크립트 코드를 HTML 페이지에서 사용할 수 있도록 한 예제입니다. HTML 페이지를 브라우저에서 실행하면 여러 API 요청을 비동기적으로 처리하며, POST 요청의 성공 및 실패 여부를 콘솔에 출력합니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise API Example</title>
</head>
<body>
<h1>Promise API Example with POST Requests</h1>
<button id="start">Start API Requests</button>
<script>
// POST로 데이터를 전송하는 API URL
const apiURL1 = 'https://jsonplaceholder.typicode.com/posts';
const apiURL2 = 'https://jsonplaceholder.typicode.com/posts';
const apiURL3 = 'https://jsonplaceholder.typicode.com/posts';
// POST 데이터를 준비하는 함수
const createPostData = (title, body, userId) => {
return JSON.stringify({
title: title,
body: body,
userId: userId
});
};
// POST 요청을 처리하는 함수 (fetch로 POST 요청)
const postData = (url, data) => {
return fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: data
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.catch(error => {
console.error(`Error posting to ${url}:`, error);
throw error;
});
};
// API 요청을 트리거하는 함수
document.getElementById('start').addEventListener('click', () => {
// 전송할 데이터를 정의
const data1 = createPostData('첫 번째 제목', '첫 번째 본문 내용', 1);
const data2 = createPostData('두 번째 제목', '두 번째 본문 내용', 2);
const data3 = createPostData('세 번째 제목', '세 번째 본문 내용', 3);
// 1. Promise.all(): 모든 요청이 성공해야만 다음 단계로 진행
Promise.all([postData(apiURL1, data1), postData(apiURL2, data2), postData(apiURL3, data3)])
.then((results) => {
console.log('Promise.all 성공:', results);
})
.catch((error) => {
console.error('Promise.all 실패:', error);
});
// 2. Promise.allSettled(): 각 요청의 성공 여부와 상관없이 모든 결과를 반환
Promise.allSettled([postData(apiURL1, data1), postData(apiURL2, data2), postData(apiURL3, data3)])
.then((results) => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`API ${index + 1} 성공:`, result.value);
} else {
console.error(`API ${index + 1} 실패:`, result.reason);
}
});
});
// 3. Promise.any(): 가장 먼저 성공한 요청만 처리
Promise.any([postData(apiURL1, data1), postData(apiURL2, data2), postData(apiURL3, data3)])
.then((result) => {
console.log('Promise.any 첫 번째 성공:', result);
})
.catch((error) => {
console.error('Promise.any 모든 요청 실패:', error.errors);
});
// 4. Promise.race(): 가장 빠르게 완료된 요청만 처리
Promise.race([postData(apiURL1, data1), postData(apiURL2, data2), postData(apiURL3, data3)])
.then((result) => {
console.log('Promise.race 첫 번째 완료:', result);
})
.catch((error) => {
console.error('Promise.race 첫 번째 실패:', error);
});
});
</script>
</body>
</html>
이 HTML 예제는 실제로 fetch를 이용하여 POST 방식으로 데이터를 전송하고, 각각의 Promise 메서드가 어떻게 동작하는지를 실시간으로 확인할 수 있도록 구성되었습니다.
이 코드는 웹 애플리케이션 개발에서 비동기 작업을 관리할 때 사용됩니다. 특히, 여러 개의 API 요청을 동시에 실행하거나, 각 요청의 결과를 개별적으로 처리해야 하는 복잡한 비동기 상황에서 매우 유용합니다. 이러한 기술은 다음과 같은 실제 상황에서 적용할 수 있습니다:
이처럼, 비동기 작업을 효율적으로 관리하는 것이 중요할 때 이러한 Promise 메서드를 적용하여 개발을 최적화할 수 있습니다.
JS : 오늘, 내일 날씨 및 온도 구현하기 (openweathermap 활용) (1) | 2024.10.31 |
---|---|
Cross-site scripting (XSS) cheat sheet (0) | 2024.05.08 |
자바스크립트 Promise 개념 및 4가지 메소드 알아보기 (4) | 2023.11.16 |
FooTable : Filter dropdown (테이블에 대한 사용자 지정 드롭다운 필터를 만드는 방법.) (6) | 2023.10.23 |
Fine Uploader 3.0 now with optional jQuery wrapper (https://tellibus.com/fineuploader/) 파일업로드 (0) | 2023.10.05 |