비동기처리란?
작업의 완료 유무와 상관 없이 동시에 다음 작업을 수행하는 처리 방식을 말한다.
(동기처리는 작업이 반드시 순서대로만 수행되는 처리 방식을 의미한다.)
비동기처리를 수행하기 위해 TS(JS)에서는 Callback Function, Promise, Async-Await 등을 이용한다.
각각이 비동기처리를 어떻게 수행하는지 순서대로 알아보자.
Callback Function
Callback Function은 특정 조건에서 실행되는 함수로, 특정 시간에 도달하거나 특정 이벤트가 실행됐을 때 시스템에서 호출하는 함수이다.
간략하게만 알아보자.
console.log('Hello Server');
setTimeout((): void => {
console.log('Hello Server 2');
}, 3000); // 3초
console.log('Hello Server 3');
setTimeout()은 특정 시간 이후에 콜백 함수를 실행시키는 내장함수이다.
만약 위 코드가 동기처리된다면 Hello Server, 2, 3 순서대로 출력되겠지만,
위와 같이 비동기처리된다.
위와 같은 Callback Function을 활용한 비동기처리의 문제점은 코드가 복잡해진다는 점이다.
let serverList: string[] = [];
setTimeout((name): void => {
serverList = [...serverList, name];
console.log(serverList);
setTimeout((name): void => {
serverList = [...serverList, name];
console.log(serverList);
setTimeout((name): void => {
serverList = [...serverList, name];
console.log(serverList);
}, 500, 'name3');
}, 500, 'name2');
}, 500, 'name1');
위와 같은 코드는 안으로 심하게 파여 흔히 '콜백 지옥(Callback hell)'이라고 표현한다.
Promise
Callback hell을 극복하기 위해 만들어진 것으로,
Pending(대기), Fulfilled(이행), Rejected(실패)의 3가지 상태가 있다.
const condition: boolean = true;
const promise = new Promise((resolve, reject) => {
if (condition) {
setTimeout(() => {
resolve('Success');
}, 1000);
// resolve('Success');
} else {
reject(new Error('Error! Condition is false'))
}
});
promise
.then((resolveData): void => console.log(resolveData))
.catch(err => console.log(err));
console.log('test')
위 코드를 통해 Promise의 사용 방법을 알 수 있다.
우선 new Promise를 통해 promise에 Promise 객체를 할당한다.
condition이 true이므로 setTimeout이 실행되는데,
promise.then에서 then은 resolve가 실행된 이후 호출된다.
즉 setTimeout()의 조건에 따라 1초가 지나기 전이 Pending(대기)상태이고, 이때제일 아래에 있는 console.log('test')가 실행된다.
이후 1초가 지나 resolve가 실행되면 'Success' 값이 then으로 전달되고 그것을 resolveData라는 매개변수로 받는다.
이 상태가 Fulfilled(이행) 상태이다.
만약 condition이 false였다면 reject가 실행되었을 것이고, catch가 호출된다. 이 상태를 Rejected(실패) 라고 한다.
조금 복잡한 형태의 코드를 통해
Promise Chaining에 대해 알아보자. (Promise를 연쇄적으로 호출하는 것을 의미한다.)
const restaurant = (callback: () => void, time: number) => {
setTimeout(callback, time);
};
const order = (): Promise<string> => { // order 객체가 string을 반환하는 Promise 객체라는 뜻이다.
return new Promise((resolve, reject) => { // Promise 객체를 반환한다
restaurant(() => { // Promise 내부 함수
console.log('레스토랑 진행 상황 - 음식 주문');
resolve('음식 주문 시작');
}, 1000);
});
}
const cook = (progress: string): Promise<string> => { // cook은 string인 progress라는 매개변수를 받아, string을 반환하는 Promise 객체라는 뜻.
return new Promise((resolve, reject) => {
console.log('레스토랑 진행 상황 - 음식 조리');
restaurant(() => {
resolve(`${progress} -> 음식 조리 중`); // 전달받은 progress에 텍스트를 붙여 resolve로 반환한다.
}, 2000);
});
}
const serving = (progress: string): Promise<string> => {
return new Promise((resolve, reject) => {
console.log('레스토랑 진행 상황 - 음식 서빙');
restaurant(()=> {
resolve(`${progress} -> 음식 서빙 중`);
}, 3000);
});
}
const eat = (progress: string): Promise<string> => {
return new Promise((resolve, reject) => {
console.log('레스토랑 진행 상황 - 음식 먹기');
restaurant(() => {
resolve(`${progress} -> 음식 먹는 중`);
}, 4000);
});
}
order() // order() 실행
.then(progress => cook(progress)) // order 내부에서 resolve가 실행되어 반환되는 값이 progress로 들어간다. progress => cook(progress)는 함수를 then의 매개변수로 넣은 것.
.then(progress => serving(progress))
.then(progress => eat(progress))
.then(progress => console.log(progress));
progress가 연쇄적으로 전달된다.
Async - Await
ES2017부터 제공되는 혁신적인 기능! 이라고 한다.
코드를 짤 때 동기식 코드처럼 사고하고 코딩할 수 있게 되었다.
우선 함수 선언부터 알아보자.
// 함수 표현식
const asyncFunction1 = async () => {
}
// // 함수 선언식
async function asyncFunction2() {
}
위와 같이 선언한다.
let asyncFunc1 = (msg: string): Promise<string> => {
return new Promise(resolve => {
setTimeout(() => {
resolve(`asyncFunc1 - ${msg}`);
}, 1000);
});
};
let asyncFunc2 = (msg: string): Promise<string> => {
return new Promise(resolve => {
setTimeout(() => {
resolve(`asyncFunc2 - ${msg}`);
}, 1500);
});
};
const asyncMain = async (): Promise<void> => {
let result = await asyncFunc1('hi');
console.log(result);
result = await asyncFunc2('hello');
console.log(result);
};
const promiseMain = (): void => {
asyncFunc1('hi').then((result: string) => {
console.log(result);
return asyncFunc2('hello');
}).then((result: string) => {
console.log(result);
});
};
asyncMain();
promiseMain();
await은 Promise가 실행될 때까지 기다리겠다는 뜻이다.
익숙한 동기 코드의 실행 방식처럼, 실행 여부를 then, catch로 분기하지 않고 코딩할 수 있다.
'Javascript, Typescript' 카테고리의 다른 글
[Javascript] 동기/비동기 정리(2) - JS 초짜가 Promise 완벽하게 이해한 방식(+Typescript로 변환까지) (0) | 2022.05.06 |
---|---|
[Javascript] 동기/비동기 정리(1) - callback 함수의 뜻과 쓰임 feat. 화살표 함수 (Typescript로 변환까지) (0) | 2022.05.05 |
[Typescript] 타입스크립트 기초 정리 #타입 #인터페이스(interface) (0) | 2022.04.04 |
자바스크립트 - 기초 정리 (3) #객체(object) #method #this #배열(array) (0) | 2022.04.04 |
자바스크립트 - 기초 정리 (2) #반복문 #switch문 #함수 #함수표현식 #화살표함수 #호이스팅 (0) | 2022.04.01 |