이번 글에서는 Promise와 async/await의 차이에 대해서 공부해보겠습니다!
동기 / 비동기 특징
- 동기의 (대략적인) 특징
- 동시에 여러 작업을 수행할 수 없다.
- 흐름을 예측하기 쉽다. 먼저 수행되고 나중에 수행되는 것들이 명확하다.
- 비동기의 (대략적인) 특징
- 동시에 여러 작업을 수행할 수 있다.
- 흐름을 예측하기 어렵다. (무엇이 먼저 완료될 지 보장할 수 없다.)
Promise
Promise는 자바스크립트에서 비동기 처리에 사용되는 객체입니다.
코드는 실행 되었지만 결과를 아직 반환하지 않은 객체라고 설명할 수 있습니다.
Promise는 3가지 상태가 있습니다.
- Pending(대기)
- Fulfilled(이행)
- Rejected(실패)
비동기 처리를 아직 수행하는 단계인 Pending,
비동기 처리가 완료되어 값을 반환한 상태인 Fulfilled,
비동기 처리가 어떠한 이유에서 실패한 상태 Rejected,
Promise의 사용 코드
const condition = true;
const promise = new Promise((resolve, reject) => {
if (condition) {
resolve('resolved');
} else {
reject('rejected');
}
});
promise
.then((res) => {
console.log(res);
})
.catch((error) => {
console.error(error);
});
위 코드를 보면, promise라는 변수에 Promise 생성자 함수를 사용하여 할당하는 것을 볼 수 있습니다.
여기서 생성자 함수는 executor 라고 불리는 특별함 함수(함수의 형태는 화살표 함수) 하나를 인자로 받습니다.
executor 함수는 resolve와 reject 라는 두 가지 인수를 받는데,
resolve를 호출하게 된다면 비동기 작업의 성공을 의미하고, reject를 호출하면 실패를 의미합니다.
Promise의 동작 처리
Promise가 끝난 후 동작을 설정할 수 있는데, 이는 then메소드와 catch메소드 입니다.
위 코드는 성공하도록 만들었기 때문에 resolve를 호출되기 때문에, then메소드의 동작만 실행됩니다.
만약, reject가 호출되면 catch메소드의 동작만 실행됩니다.
async / await
async/await은 Promise 와 굉장히 밀접한 연관을 가지고 있는데,
executor에 몇 가지 규칙만 적용한다면 Promise 객체를 리턴하는 함수를 async/await로 변환할 수 있습니다.
async
async 키워드는 함수를 선언할 때 붙여줄 수 있습니다.
- 함수에 async 키위드를 붙이고, Promise 생성자 함수를 제거합니다.
- resolve(value); 를 return value; 로 변경합니다.
- reject(error); 부분을 throw new Error(); 로 수정합니다.
await
await은 Promise가 fulfilled 또는 rejected이 될 때까지 기다리는 함수입니다
위 코드를 수정해 보면 아래와 같습니다.
(async () => {
const condition = true;
const promise = new Promise((resolve, reject) => {
if (condition) {
resolve('resolved');
} else {
reject('rejected');
}
});
try {
const result = await promise;
console.log(result);
} catch (err) {
console.error(err);
}
})();
Promise를 사용했던 코드를 익명 함수에 async/await 를 사용하였습니다.
async 익명 함수의 await으로 Promise의 반환 값을 result 변수에 담아 출력하는 예제입니다.
여기서는 Promise와 다르게 try-catch()문으로 동작을 처리하는 것을 볼 수 있습니다.
왜 async/await을 쓸까 ?
1. async는 에러 위치를 찾기 쉽습니다.
만약, Promise를 여러번 호출해야하는 경우가 생긴다고 한다면
어떤 then메소드에서 오류가 났는지 확인하기 어렵습니다.
function sample() {
return sampleFunc()
.then(data => return data)
.then(data2 => return data2)
.then(data3 => return data3)
.catch(err => console.log(err)) // 결과적으로 문제가 발생했다
}
async function sample() {
const data1 = await sampleFunc(); // 문제 발생시 data1값이 유효치 않음
const data2 = await sampleFunc2(data1);
return data2;
}
2. async 코드는 가독성이 좋습니다.
아래의 코드를 보면 then에 비해 async를 사용했을 때, 짧아지는 것을 볼 수 있습니다.
또한, 리턴값을 변수에 담아 사용하므로 직관적으로 변수를 인식할 수 있습니다.
function printAnimals() {
return getAnimals()
.then(data => {
if (data.property) {
return sampleFunc1(data)
.then(anotherData => {
console.log(anotherData)
})
}else {
console.log(data)
}
})
}
async function printAnimals() {
const animals = await getAnimals();
if (animals.property) {
const sampleData = await sampleFunc1(animals);
console.log(sampleData);
}else {
console.log(animals);
}
}
3. async는 에러 핸들링에 유리합니다.
이번에는 printAnimals()에서 에러가 발생한 게 아니라, JSON.parse에서 에러가 발생했다고 가정합니다.
이 경우에는 try-catch()문을 사용했음에도, then메소드를 사용하여 catch문을 추가로 작성해야 합니다.
그러나 async를 사용하게 되면 try-catch문 하나로 처리할 뿐만 아니라,
직관적으로 어디서 오류가 났는지 파악할 수 있습니다.
function printAnimals() {
try {
getAnimals()
.then((response) => {
const data = JSON.parse(response); // 여기서 에러 발생한다고 가정
console.log(data);
})
.catch((err)=> { // 추가적인 에러
console.log(err)
})
}
catch(err) {
console.log(err)
}
}
async function printAnimals() {
try {
const data = await JSON.parse((getAnimals())
console.log(data);
}
catch(err) {
console.log(err)
}
}
'JavaScript' 카테고리의 다른 글
불변성은 왜 지켜야할까? (0) | 2022.04.27 |
---|---|
함수 스코프와 블록 스코프 (0) | 2022.04.24 |
[JavaScript] 함수 표현식 VS 함수 선언식 (0) | 2022.01.25 |
[JavaScript] 화살표 함수 (Arrow Function) (0) | 2021.09.08 |
[JavaScript] 클로저 (Closure) (0) | 2021.09.08 |
댓글