면접답변
Promise와 Async · Await의 차이점
에러 핸들링 측면에서는 Promise를 활용할 시에는 .catch() 문을 통해 에러 핸들링이 가능합니다.
Async · Await은 에러 핸들링 할 수 있는 기능이 없어 try-catch() 문을 활용해야합니다.
코드 가독성
Promise의 .then()을 활용하지만 코드가 길어지면 길어질수록, .then지옥으로 코드가독성이 않좋기에
Async · Await 을 활용한 코드가 가독성이 좋습니다.
자료
자바스크립트는 동기적으로 실행합니다.
즉 순차적으로 실행된다. 근데 만약에 아래처럼 무거운 함수가 있습니다.
function otherFunc({
console.log('우리는 otherFunc안에 있습니다.)
})
console.log('Start')
otherFunc()
for(let i =0; i< 100000000; i++){
console.log(i);
}
console.log(end)
그럼 엔드가 출력되기위해 저 무거운 함수를 다돌아야 합니다.
1. 자바스크립트에서 비동기 처리는 왜 필요할까?
자바스크립트는 비동기언어이다. 즉, 코드 하나가 처리될때 지연시간이 발생한다면 이후의 태스크들은 블로킹 되어집니다. 서버에 데이터를 요청하는 등의 대기시간이 긴 작업의 경우에는 지연기간을 해서하기위한 병렬적 함수 실행이 필요합니다.
이때 나오는 개념이 비동기처리입니다.
function getData() {
// 비동기적으로 데이터를 가져오는 네트워크 요청을 가정
fetch('https://example.com/data')
.then(response => response.json())
.then(data => {
return data; // 이 라인은 fetch의 결과 처리가 완료된 후에 실행됩니다.
});
// 여기서 함수는 fetch 요청이 완료되기를 기다리지 않고 끝나므로, 반환값이 없습니다.
}
function printData() {
const data = getData();
console.log(data); // getData()에서 바로 반환된 값이 없으므로, undefined가 출력됩니다.
}
위의 코드에서 getData() 함수가 서버에서 데이터를 가져오는 함수라고 가정 할때 getData()는 fetch 요청의 결과를 기다리지 않고 종료되므로, printData()에서 console.log(data);를 실행했을 때, getData()에서 반환되는 값은 undefined입니다. 이 문제를 해결하려면 getData()에서 Promise를 반환하게 하고, printData()에서 이 Promise를 기다릴 필요가 있습니다:
2. 비동기 처리 방식
비동기 처리방식은 크게 async - await 방식 pomise 방식을 활용한다.
Promise에 비해 가독성이 좋고, 문법이 간결하다.
아래의 코드는 promise 방식과 async - await 방식을 활용한 코드입니다.
promise
function getText() {
return new Promise((resolve, reject) => {
$.get("API 주소", function(res) {
if (res) {
resolve("데이터를 성공적으로 불러왔습니다");
} else {
reject("데이터를 불러오는데 실패했습니다");
}
});
});
}
function printText() {
getText()
.then(data => {
console.log(data);
})
.catch(error => {
console.error(error);
});
}
async - await
function getText() {
return newData((resolve, reject) => {
$.get("API 주소", function((res) => {
if (res) {
resolve("데이터를 성공적으로 불러왔습니다");
}
});
reject("데이터를 불러오는데 실패했습니다");
});
}
async function printText() {
const text = await getText();
console.log(text);
}
이렇게 짧은 코드에서는 가독성과 간결성이 async - await가 좋다는 것을 느끼기 힘듭니다.
하지만 추가적인 데이터 처리방식이 들어가면 promise는 .then을 통해 많은 들여쓰기와 복잡한 코드로 보입니다.
반면 Async · Await과 같은 경우, 응답 값을 명시적인 변수에 담아 사용하므로 직관적인 변수를 인식할 수 있으며, 간결하다는 장점을 가지고 있습니다.
function getText() {
return newData((resolve, reject) => {
$.get("API 주소", function((res) => {
if (res) {
resolve({name : "홍길동", property : "홍길동의 특성"});
}
});
reject("데이터를 불러오는데 실패했습니다");
});
}
function printText_Promise() {
return getText()
.then((data) => {
if (data.property) {
return sampleFunc1(data)
.then(anotherData => {
console.log(anotherData);
}
} else {
console.log(data);
}
}
}
async function printText_Async() {
const text = await getText();
if (text.property) {
const sampleData = await sampleFunc1(text);
console.log(sampleData);
} else {
console.log(text);
}
}
에러헨들링에 유용
function fetchData() {
return new Promise((resolve, reject) => {
$.get("API_URL", function(response) {
if (response) {
resolve({name: "홍길동", property: "특성"});
} else {
reject("데이터 로드 실패");
}
}).fail(() => {
reject("API 요청 실패");
});
});
}
function displayDataUsingPromise() {
fetchData()
.then(data => {
try {
const person = JSON.parse(data);
console.log(person);
} catch (parseError) {
console.error("JSON 파싱 에러:", parseError);
}
})
.catch(error => {
console.error("에러 발생:", error);
});
}
async function displayDataUsingAsync() {
try {
const data = await fetchData();
const person = JSON.parse(data);
console.log(person);
} catch (error) {
console.error("에러 발생:", error);
}
}
위의 코드에서 try 문에 들어가있는 .catch 코드, try 문의 .catch 코드가 보일 것이다. 코드가 직관적이지 않으며 동시에 에러를 처리하는 catch 문의 중복성이 눈에 띄고 있다.
1.Promise 예제: .catch()를 사용하여 오류를 캡처합니다. 이 방법은 여러 .then() 호출이 체인될 때 각 단계에서 발생할 수 있는 오류를 한 곳에서 처리할 수 있게 해줍니다. 그러나, 각 .then()에서 발생할 수 있는 복잡한 오류를 구체적으로 파악하고 디버그하기는 더 어려울 수 있습니다.
// Promise를 사용한 예제
function samplePromise() {
return sampleFunc()
.then(data => data)
.catch(err => {
console.error("Promise에서 오류 발견:", err);
});
}
2. async/await 예제: try...catch 블록을 사용하여 오류를 처리합니다. 이 방식은 일반적인 동기 코드의 오류 처리와 매우 유사하며, 어떤 함수 호출에서 오류가 발생했는지 정확하게 알 수 있게 해줍니다. 코드의 흐름을 더 쉽게 따라갈 수 있으며, 각 단계에서의 오류 처리를 개별적으로 할 수 있습니다.
// async/await를 사용한 예제
async function sampleAsync() {
try {
const data = await sampleFunc();
console.log(data);
} catch (err) {
console.error("async/await에서 오류 발견:", err);
}
}
그러면 Promise 비에 async/await이 압도적으로 좋은데 promise 안쓰냐 ?
promise 장점
1. 병렬 처리
Promise는 **Promise.all()**과 같은 정적 메소드를 통해 여러 비동기 작업을 병렬로 실행하고, 모든 작업이 완료되기를 기다린 후 결과를 한 번에 처리할 수 있는 기능을 제공합니다. 이는 여러 리소스를 동시에 가져오거나, 여러 API 호출의 결과가 동시에 필요한 경우 매우 효율적입니다. **async/await**도 이러한 패턴을 사용할 수 있지만, Promise를 사용하는 것이 더 자연스러울 수 있습니다.
2. 커스텀 비동기 흐름 제어
Promise를 사용하면 비동기 작업의 흐름을 더 세밀하게 제어할 수 있습니다. 예를 들어, 비동기 작업의 체이닝, 조건부 실행, 또는 동적으로 Promise를 생성하고 관리하는 복잡한 시나리오에서는 Promise가 더 유연한 해결책을 제공할 수 있습니다.
3. 에러 처리의 유연성
**async/await**를 사용할 때는 try/catch 블록으로 에러를 처리합니다. 이는 매우 직관적이고 편리하지만, 모든 에러를 동일한 방식으로 처리해야 하는 경우에는 제한적일 수 있습니다. 반면, Promise는 .catch() 메소드를 통해 각각의 비동기 작업에 대해 보다 세밀한 에러 처리를 구현할 수 있습니다. 또한, .then(), .catch(), .finally() 메소드를 통해 성공, 실패, 완료 시점에 실행할 콜백 함수를 지정하는 것이 더 명확할 수 있습니다.
4. 프로미스 컴포지션
Promise를 사용하면, 작은 단위의 비동기 작업을 컴포지션하여 더 큰 비동기 프로세스를 구성할 수 있습니다. 이는 코드의 재사용성과 모듈성을 향상시킬 수 있으며, 복잡한 비동기 로직을 더 관리하기 쉽게 만들어 줍니다.
5. 호환성
구형 JavaScript 환경이나 라이브러리에서는 **async/await**를 지원하지 않을 수 있습니다. 이 경우, Promise는 여전히 비동기 작업을 효과적으로 처리할 수 있는 유일한 수단일 수 있습니다.
결론
**async/await**가 일반적인 사용 사례에서 코드의 가독성과 작성 편의성을 크게 개선하지만, Promise는 병렬 처리, 커스텀 비동기 흐름 제어, 세밀한 에러 처리 등 특정 상황에서 더 나은 선택이 될 수 있습니다. 따라서, 두 기술은 상호 배타적인 것이 아니라 상호 보완적이며, 상황에 따라 적절히 선택하여 사용하는 것이 중요합니다.
참고자료
https://klmhyeonwooo.tistory.com/54?category=1135084
https://www.youtube.com/watch?v=gZ7kISGdHa0
'면접준비' 카테고리의 다른 글
[면접-JS] var,let,const 차이 with호이스팅 (0) | 2024.05.08 |
---|