비동기란 특정 코드의 연산이 끝날 때까지 코드의 실행이 끝나지 않은 상태에서, 순차적으로 다음 코드를 먼저 실행하는 JS의 특성이다. 요청에 대한 결과를 기다리지 않고 다음 코드를 실행한다는 것이다.
- 대기(pending): 이행하거나 거부되지 않은 초기 상태.
- 이행(fulfilled): 연산이 성공적으로 완료됨.
- 거부(rejected): 연산이 실패함.
function asyncTask(success) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (success) {
resolve("Task completed successfully!");
} else {
reject("Task failed!");
}
}, 2000); // 2초 후에 작업이 완료
});
}
console.log("Task started...");
asyncTask(true) // true를 전달하면 성공, false를 전달하면 실패
.then(result => {
console.log(result); // 성공했을 때 실행
})
.catch(error => {
console.error(error); // 실패했을 때 실행
})
.finally(() => {
console.log("Task finished"); // 성공 여부와 상관없이 실행
});
- Pending (대기): 비동기 작업이 아직 완료되지 않은 상태.
- Fulfilled (성공): 비동기 작업이 성공적으로 완료된 상태.
- Rejected (실패): 비동기 작업이 실패한 상태.
이전까지 비동기화 작업은 주로 callback을 사용했다. 그러나 callback은 몇가지 문제가 있어 이를 보완하기 위해 promise가 등장합니다.
1. 비동기통신 응답 전달
const get = url => {
const xhr = new XMLHttpRequest() // XMLHttpRequest 객체생성
xhr.open('GET', url) // HTTP요청 초기화
xhr.send() // HTTP요청 전송
xhr.onload = () => { // onload 이벤트 핸들러 프로퍼티에 바인딩하고 종료
if (xhr.status === 200) {
return xhr.response
}
console.error(`${xhr.status} ${xhr.statusText}`)
}
}
const response = get('https://woo06.tistory.com/6')
console.log(response) // undefined
response를 반환하지만 undefinded인 이유는 응답을 받기 전에 이미 console.log가 수행되기 때문입니다.
Promise를 이용한 수정코드
const get = url => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest(); // XMLHttpRequest 객체 생성
xhr.open('GET', url); // HTTP 요청 초기화
xhr.send(); // HTTP 요청 전송
xhr.onload = () => { // onload 이벤트 핸들러 설정
if (xhr.status === 200) {
resolve(xhr.response); // 요청이 성공하면 resolve로 응답 반환
} else {
reject(new Error(`${xhr.status} ${xhr.statusText}`)); // 오류 발생 시 reject
}
};
xhr.onerror = () => {
reject(new Error('Request failed'));
};
});
};
get('https://woo06.tistory.com/6')
.then(response => {
console.log(response); // 응답이 성공적으로 도착하면 출력
})
.catch(error => {
console.error('Error:', error); // 오류가 발생하면 출력
});
2. 순차적 통신 수행
const get = (url, callback) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
callback(null, xhr.response); // 성공적으로 데이터를 가져온 경우
} else {
callback(new Error(`${xhr.status} ${xhr.statusText}`), null); // 오류 발생
}
};
xhr.onerror = () => {
callback(new Error('Request failed'), null); // 요청 실패
};
};
// 여러 데이터를 순차적으로 받는 코드 (콜백 방식)
get('https://woo06.tistory.com/1', (error, response1) => {
if (error) {
return console.error('Error fetching first response:', error);
}
console.log('First response:', response1);
get('https://woo06.tistory.com/2', (error, response2) => {
if (error) {
return console.error('Error fetching second response:', error);
}
console.log('Second response:', response2);
get('https://woo06.tistory.com/3', (error, response3) => {
if (error) {
return console.error('Error fetching third response:', error);
}
console.log('Third response:', response3);
});
});
});
Promise를 이용한 수정코드
const get = url => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
resolve(xhr.response);
} else {
reject(new Error(`${xhr.status} ${xhr.statusText}`));
}
};
xhr.onerror = () => {
reject(new Error('Request failed'));
};
});
};
// 여러 데이터를 순차적으로 받는 코드 (async/await)
const fetchSequentialData = async () => {
try {
const response1 = await get('https://woo06.tistory.com/1');
console.log('First response:', response1);
const response2 = await get('https://woo06.tistory.com/2');
console.log('Second response:', response2);
const response3 = await get('https://woo06.tistory.com/3');
console.log('Third response:', response3);
} catch (error) {
console.error('Error:', error);
}
};
fetchSequentialData(); // 순차적으로 데이터를 가져오는 함수 호출
Promise.all
Promise.all은 JavaScript에서 Promise 객체를 처리할 때 사용하는 유틸리티 함수로, 여러 개의 Promise를 병렬로 실행하고, 모든 Promise가 성공적으로 이행(Fulfilled)되면 결과를 반환합니다. 이 과정에서 결과는 입력한 순서대로 반환됩니다.
const get = async (url) => {
const response = await fetch(url); // 요청을 보냄
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response;
};
const fetchSequentialData = async () => {
try {
// 병렬로 요청 실행
const [response1, response2, response3] = await Promise.all([
get('https://woo06.tistory.com/2'),
get('https://woo06.tistory.com/4'),
get('https://woo06.tistory.com/5'),
]);
console.log('First response:', response1);
console.log('Second response:', response2);
console.log('Third response:', response3);
} catch (error) {
console.error('Error:', error);
}
};
fetchSequentialData();
동작 방식
- 병렬 실행
- 결과 순서 보장
- 하나라도 실패하면 전체 실패
주요 특징
- 병렬로 실행되지만 결과는 입력 배열 순서를 유지합니다.
- 최초 실패 시 즉시 reject됩니다. 첫 번째 실패한 Promise의 이유를 반환하며, 나머지 Promise의 상태는 알 수 없습니다.
- 입력값에 Promise가 아닌 값도 포함 가능
Promise.all은 Promise가 아닌 값도 처리할 수 있으며, 해당 값은 자동으로 resolve된 것으로 간주합니다.
const promise1 = Promise.resolve(10); // 이미 이행된 Promise
const promise2 = new Promise((resolve) => setTimeout(() => resolve(20), 1000)); // 1초 후 이행
const nonPromiseValue = 30; // Promise가 아님
Promise.all([promise1, promise2, nonPromiseValue])
.then((results) => {
console.log(results); // [10, 20, 30]
})
.catch((error) => {
console.error('Error:', error);
});
Promise.allSettled
Promise.allSettled는 **모든 Promise가 이행(fulfilled)**되거나 **거부(rejected)**된 후에, 각각의 결과를 나타내는 객체를 반환하는 메서드입니다.
주요 특징
- 모든 Promise가 끝날 때까지 기다림:
- Promise.allSettled는 Promise가 성공하거나 실패하더라도 모든 Promise가 완료될 때까지 기다립니다.
- Promise.all과는 달리, 하나의 Promise가 거부되더라도 전체가 실패하지 않고 각각의 상태를 개별적으로 제공합니다.
- 결과 형식:
- 결과는 배열로 반환되며, 각 항목은 다음 중 하나의 상태를 가집니다:
- { status: 'fulfilled', value: ... }: 성공한 Promise.
- { status: 'rejected', reason: ... }: 실패한 Promise.
- 결과는 배열로 반환되며, 각 항목은 다음 중 하나의 상태를 가집니다:
const get = async (url) => {
const response = await fetch(url); // 요청을 보냄
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response;
};
Promise.allSettled(
[
get('https://woo06.tistory.com/2'),
get('https://woo06.tistory.com/4'),
get('https://woo06.tistory.com/5'),
]
).then((results) => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Promise ${index + 1} fulfilled with value: ${result.value}`);
} else if (result.status === 'rejected') {
console.log(`Promise ${index + 1} rejected with reason: ${result.reason}`);
}
});
});
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise
Promise - JavaScript | MDN
Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타냅니다.
developer.mozilla.org
[JavaScript] 비동기 처리의 의미, 콜백 패턴의 문제점, Promise의 등장 배경
기능 구현만을 위해 백엔드 데이터를 받아오기 위해 기계적으로 썼던 fetch, then 등 자바스크립트의 비동기 처리를 위한 문법을 다시 들여다보고 기본을 다잡고자 정리해보려 한다. 프로미스란
velog.io
'WEB개발 > JS&HTML' 카테고리의 다른 글
[JS] Async, Await, Fetch, PromiseAll (0) | 2023.03.06 |
---|---|
[JS, JAVA] 정규식 (0) | 2022.06.13 |
[JS] Engine, Event Loop (0) | 2021.06.24 |
[html] input(inputmode, event, pattern) (0) | 2021.06.24 |
[JS] JavaScript 유용한 Array 함수 + JAVA stream() (0) | 2021.06.23 |