의도: Promise에 대한 이해도를 확인하는 질문
팁: Promise.race()를 언급하는 게 정답이다.
나의 답안
Promise를 사용해 타임아웃 기능을 구현할 때는 보통
Promise.race()메서드를 사용합니다.
Promise.race()는 여러 개의 Promise 중에서 가장 먼저 끝나는 것 하나만 결과로 반환하기 때문에, 비동기 작업과 타이머를 동시에 실행시켜서 둘 중 먼저 끝나는 걸 기준으로 처리할 수 있습니다.예를 들어, 어떤 요청이 일정 시간 안에 완료되지 않으면 타이머 쪽이 먼저 완료돼서 에러를 발생시키도록 만들면, 결과적으로 타임아웃 기능을 구현할 수 있습니다.
이렇게 하면 네트워크 요청이나 오래 걸리는 비동기 작업에서 예측 가능한 제어 흐름을 만들 수 있고, 사용자 경험도 훨씬 안정적으로 관리할 수 있습니다.
주어진 답안 (모범 답안)
Promise.race()를 사용하면 됩니다.
이 함수의 기능은, 인자에 비동기 함수를 넣어주게 되면 넣어준 함수들 중 가장 빠르게 resolve되는 함수의 결과만을 가져오게 됩니다.그러면 여기에 내가 사용할 비동기 함수와,
setTimeout을 함께 넣어주게 된다면 비동기 함수와setTimeout둘 중 먼저 끝나는 쪽을 반환해주게 됩니다.
만약setTimeout을 3초로 정해둔다면 3초 안에 비동기 함수가 resolve되지 않을 시 타임아웃 판단을 내리도록 구현할 수도 있습니다.
Promise.race()의 개념Promise.race()는 여러 개의 프로미스 중에서 가장 먼저 완료되는(fulfilled 또는 rejected) 프로미스를 반환하는 메서드이다.Promise.race()의 동작 방식Promise.race(iterable);
iterable: 배열 또는 이터러블 객체로, 여러 개의 Promise를 포함할 수 있다.Promise의 상태와 결과를 그대로 반환한다.즉, 가장 먼저 완료되는 Promise의 결과를 가져오므로, 나머지 Promise들은 그대로 남아 있지만, race()의 결과에 영향을 미치지 않는다.
Promise.race() 예제가장 빠른 Promise가 결과를 반환하는 예제
const p1 = new Promise((resolve) => setTimeout(resolve, 500, "첫 번째 완료"));
const p2 = new Promise((resolve) => setTimeout(resolve, 300, "두 번째 완료"));
const p3 = new Promise((resolve) => setTimeout(resolve, 1000, "세 번째 완료"));
Promise.race([p1, p2, p3]).then(console.log);
// 출력: "두 번째 완료"
p2가 300ms로 가장 먼저 완료되므로, Promise.race()는 "두 번째 완료"를 반환한다.Promise가 reject 되는 경우
가장 먼저 reject된 Promise가 있으면, .catch()로 처리할 수 있다.
const p1 = new Promise((resolve) => setTimeout(resolve, 500, "성공"));
const p2 = new Promise((_, reject) => setTimeout(reject, 300, "실패"));
Promise.race([p1, p2]).then(console.log).catch(console.error);
// 출력: "실패"
p2가 300ms 후 reject되므로, .catch()로 에러 처리된다.Promise.race()에 즉시 완료되는 Promise가 포함된 경우
const p1 = Promise.resolve("즉시 완료");
const p2 = new Promise((resolve) => setTimeout(resolve, 1000, "1초 후 완료"));
Promise.race([p1, p2]).then(console.log);
// 출력: "즉시 완료"
Promise가 있다면, 그것이 가장 먼저 완료된 것으로 간주된다.Promise.race()의 활용 사례네트워크 요청의 타임아웃 설정
네트워크 요청이 너무 오래 걸릴 경우, 일정 시간이 지나면 자동으로 실패하게 설정할 수 있다.
function fetchWithTimeout(url, timeout) {
const fetchPromise = fetch(url).then((res) => res.json());
const timeoutPromise = new Promise(
(_, reject) => setTimeout(() => reject("요청 시간이 초과되었습니다!"), timeout)
);
return Promise.race([fetchPromise, timeoutPromise]);
}
fetchWithTimeout("https://jsonplaceholder.typicode.com/todos/1", 2000)
.then(console.log)
.catch(console.error);
fetch)이 2초 안에 완료되지 않으면 "요청 시간이 초과되었습니다!"라는 에러가 발생한다.빠른 응답 서버 선택 (백업 서버)
여러 개의 서버 중 가장 빠른 응답을 반환하는 서버를 선택할 때 활용할 수 있다.
const server1 = fetch("https://api.server1.com/data");
const server2 = fetch("https://api.server2.com/data");
Promise.race([server1, server2])
.then((response) => response.json())
.then(console.log)
.catch(console.error);
server1과 server2 중 가장 빠른 응답을 제공하는 서버의 데이터를 사용한다.Promise.race()의 주의할 점Promise들은 계속 실행된다.race()에서 반환되지 않은 Promise는 취소되지 않고 계속 실행된다.Promise.race()에서 가장 먼저 reject된 Promise가 있다면, 이를 .catch()로 잡아야 한다.Promise.race() vs. Promise.all() vs. Promise.any()| 메서드 | 설명 | 성공 조건 | 실패 조건 |
|---|---|---|---|
Promise.race() | 가장 먼저 완료된 Promise를 반환 | 첫 번째 완료된 Promise | 첫 번째 reject된 Promise |
Promise.all() | 모든 Promise가 완료되면 결과 배열 반환 | 모든 Promise가 성공해야 함 | 하나라도 reject되면 전체 실패 |
Promise.any() | 하나라도 resolve되면 그 값을 반환 | 첫 번째 resolve된 Promise | 모든 Promise가 reject될 때 실패 |
Promise.race()는 가장 빨리 완료된 Promise의 결과를 반환하므로, 타임아웃 구현, 백업 서버 요청 등 빠른 응답이 중요한 경우에 유용하다.race()를 사용하면 나머지 Promise가 계속 실행되므로, 필요할 경우 추가적인 취소 로직이 필요하다.Promise.all(), Promise.any()와 비교하여 언제 사용할지 결정하는 것이 중요하다.