1. js는 동기적인 언어이다?
- 동기적이라는 말은 작업을 순서대로 처리하는 걸 말한다.
- 자바스크립트는 동기적인 언어지만, 때로는 비동기적으로 처리한다.
- 만약 자바스크립트에 많은 양의 데이터를 요청하면, 응답을 받기위해 많이 대기를 해야한다.
- 이 경우에는 데이터 응답을 받기 전까지 다른 작업을 수행할 수 없는 문제가 발생한다.
- 그렇기 때문에 이러한 경우에는 자바스크립트는 비동기적으로 작업을 처리한다.
하지만 비동기적으로 작업을 처리하는 과정에서 문제가 발생하는데, 예시를 함께보자
getAnimals()
는 서버에서 데이터를 요청하여 animals를 가져오는 메소드이다.- 만약
getAnimals()
를 사용해 animals데이터를 변수에 담고 출력한다면? 어떻게 될까?
function printAnimals() {
const animals = getAnimals();
console.log(animals);
}
printAnimals();
- 앞서 언급했듯이 js에서 데이터 요청과 같이 응답에 시간이 걸리는 작업에는 비동기 처리를 한다.
- 그렇기 때문에
getAnimals()
를 실행이 끝나지 않은 상태에서 다음 코드를 실행하므로 undefined가 출력된다.
function printAnimals() {
const animals = getAnimals(); // 1. 너 오래 걸리는구나?
console.log(animals); // 2. 다음 코드를 먼저 처리할게!
}
printAnimals(); // 3. undefined
- js에서 매번 데이터 응답을 비동기적으로 처리한다면, 응답 데이터를 사용할 수 없다.
- 그렇기에 우리는 그에 대한 대안으로 promise, async await를 사용하는 것이다.
그렇다면 promise, async await는 무엇일까? 한 번 알아보자!
2. 비동기에 대처하는 promise, async await
1) promise
(1) 프로미스란?
- 프로미스는 비동기 처리를 위해 사용되는 객체이다.
- 프로미스를 사용하면 비동기 메소드를 동기 메소드로 처리할 수 있다.
(2) 프로미스의 3가지 상태
- 프로미스는 총 3가지 상태가 존재하며 설명은 아래와 같다.
- 대기(pending): 처리 대기 상태
- 이행(fulfilled): 비동기 처리를 성공하여 결과를 반환해 준 상태
- 거부(reject): 비동기 처리를 실패하여 오류가 발생한 상태
A. 대기 상태
new Promise()
를 이용해 프로미스 객체를 생성한 시점이다.
new Promise();
B. 이행 상태
- 비동기 처리가 성공하여
resolve()
가 실행된 상태로, 이를 이행 상태라고 한다.
function printNumber(n) {
return new Promise((resolve, reject) => {
const number = n + 1;
resolve(number); // resolve == 비동기처리 성공!
})
}
resolve()
에 전달한 파라미터는then()
에서 사용할 수 있다.
printNumber(1).then((n) => console.log(n)); // 2
C. 거절 상태
- 비동기 처리가 실패하여
reject()
가 실행된 상태로, 이를 거절 상태라고 한다. catch()
에서 에러원인을 확인할 수 있다.- 아래 코드는 의도적으로 number가 3일 때
reject()
를 실행했다.
function printNumber(n) {
return new Promise((resolve, reject) => {
const number = n + 1;
if (number === 3) {
let error = new Error();
error.name = 'ValueIsThreeError';
return reject(error);
}
resolve(number);
})}
printNumber(2).catch(e => console.error(e)); // error: ValueIsThreeError
(3) 프로미스 사용 예시
프로미스는 비동기 처리를 성공(
resolve
)할 수도, 실패(reject
)할 수도 있다. 그렇다면 실제 비동기 처리를 할 때 프로미스는 어떻게 사용해야할까? 바로then
,catch
를 사용하는 것이다.
- 우리는
getApartmentInfo()
를 사용해 아파트 정보를 받고, 결과를 출력하고자 한다. - 처리가 성공했을 때는
resolve()
에 응답값을 넘기고, 실패했을 시reject()
에 에러 메시지를 넘겨준다.
function getApartmentInfo() {
return new Promise(function(resolve, reject) {
$.get('url주소', (response) => {
if (response) resolve(response); // 성공시 응답값을 넘김
reject(new Error("InValid Request Error")); // 실패시 에러메시지를 넘김
})
})
}
- 프로미스 처리가 성공하고 난 뒤,
then()
에서 그 응답 결과를 사용할 수 있다. - 하지만 만약 프로미스 처리가 실패했다면,
catch()
를 사용 하여 에러 메시지를 확인할 수 있다.
getApartmentInfo()
.then((data) => { // 성공시 응답값을 출력
console.log(data);
})
.catch((error) => { // 실패시 에러 메시지를 출력
console.error(error);
})
2) async await
(1) async await란?
async await
도promise
처럼 비동기 처리를 위해 사용된다.promise
를 더 쉽게 사용할 수 있는 방법이다.
(2) async await 사용법
- 사용법은 간단하다.
- 동기처리를 할 함수 앞에
async
를, 그리고 비동기 대상 앞에await
를 붙여주면 된다.
function getData() {
// 서버에서 데이터를 요청하는 함수
}
async function printData() { // 1. 동기적으로 처리할거야
const data = await getData(); // 2. getData 처리를 기다릴거야
console.log(data); // 3. getData처리 성공 후 실행할 코드이지!
})
}
어? 그렇다면 에러 핸들링은 어떻게 하나요?
- 만약 비동기 처리 중 발생하는 에러에 대처하고 싶다면
try~catch
문을 사용하면 된다. - 아래 코드에서는 에러상황을 확인하기 위해 throw로 에러를 발생시켰다.
function getData() {
let error = new Error();
error.name = 'Error';
throw error; // throw를 사용해 에러를 발생
}
try
에서 로직을 처리하던 중 에러가 발생하면catch
에서 에러 핸들링 할 수 있다.
async function printData() {
try {
const data = await getData();
console.log(data);
}catch(e) {
console.error(e);
}
}
printData(); // Error
(3) 비동기 처리를 동시에 할 때, promise.all
- 아래와 같이 과일, 고기, 채소에 대한 데이터를 가져오는 메소드가 있다.
- 이 메소드들은 서버에서 데이터를 요청하므로, 많은 대기 시간을 요한다.
- 이 때문에
js
에서는 이 메소드들을 비동기로 작업할텐데, 이를 방지하지 위해async await
를 쓸 예정이다. - 하지만 여기서 그치지 않고 이 메소드들을 동시에 처리하고 싶다면 어떻게 해야할까?
function getFruit() { ... };
function getMeat() { ... };
function getVegetable() { ... };
promise.all()
을 사용하면 된다!- 사용방법은 아래와 같이
promise.all()
에 비동기 처리할 메소드를 배열 안에 넣어주면 된다.
async function printFood() {
const results = await promise.all([getFruit(), getMeat(), getVegetable()]);
console.log(results);
}
- 만약 각각의 결과를 별도의 변수에 담고 싶다면 배열을 사용하면 된다.
async function printFood() {
const [fruit, meat, vegetable] = await promise.all([
getFruit(),
getMeat(),
getVegetable(),
]);
console.log(fruit, meat, vegetable);
}
(4) 제일 빨리 끝난 처리만, promise.race
promise.race
는 가능한 빨리 끝난 하나의 결과만 반환한다.- 만약 가장 먼저 끝난
promise
가 실패하면, 실패 결과만 반환한다.
function getFruit() { ... }; // 처리 1초 걸림
function getMeat() { ... }; // 처리 2초 걸림
function getVegetable() { ... }; // 처리 3초 걸림
async function printFood() {
const results = await promise.race([getFruit(), getMeat(), getVegetable()]);
console.log(results); // getFruit 결과만 반환
}
promise
에서는then()
을 사용해 비동기 처리 결과를 이용할 수 있었고,async await
에서는await
구문 다음에 처리 결과를 이용해주면 되었다. 그런데 기존에 promise가 존재했는데 async await는 어떤 장점 때문에 추가된걸까? 다음 포스팅에서는 이 둘의 차이점에 대해 알아보겠다.
반응형
'개발 기술 > 개발 이야기' 카테고리의 다른 글
랙시컬 스코프(정적 스코프)는 무엇일까? (0) | 2021.11.22 |
---|---|
promise와 async await의 차이점 (0) | 2021.11.17 |
프로토타입 (feat. 매운 맛🔥) (0) | 2021.11.04 |
프로토타입이란? (feat. 순한 맛 🌝) (0) | 2021.11.02 |
클래스(class)는 무엇인가 (0) | 2021.10.31 |
댓글