타입스크립트 9일차 - 비동기

프로세스와 스레드

비동기에 관한 이야기를 하기 전에 OS시간에 배웠던 프로세스와 스레드의 간단한 차이에 대해 알아보겠습니다.

프로세스는 간단히 프로그램에 대한 인스턴스를 말합니다. 그래서 운영체제로 부터 실행할 공간을 할당받고 관리하에 놓이게 됩니다.

스레드는 간단히 프로세스 내에서 실행되는 동작의 흐름으로 보통 일(Task)의 단위라고 얘기합니다. 그래서 프로세스내에서 스레드가 실행되며 주어진 일을 진행하고 프로세스의 관리를 받습니다.

그런데 하나의 프로세스와 하나의 스레드만 가지고 실행을 하면 요즘 8코어도 가성비가 좋네마네 하는 세상인데 1개의 프로세스와 스레드만 실행하기에는 공간이 너무 남아돕니다.

그래서 프로세스를 여러개 쓰는 작업은 OS의 시스템 콜이 필요하게 되고 상대적으로 부담을 주게 됩니다. 그러다보니 그냥 스레드를 여러개 쓰고 프로세스 하나만 타이트하게 관리하는 것이 좋겠다는 생각을 하게 되었습니다. 물론 관리도 쉽고요.

이렇게 해서 멀티 프로세싱보다는 멀티쓰레드를 많이 사용하게 되었습니다.

쉽게 예를 들면 직원이 한명이 아닌 식당에서 주문을 했을 때 주문받는사람이 주문받고나서 음식만들고 서빙까지 한다면 너무 비효율적이겠죠. 손님이 1명이라면 나머지는 놀고 있는데 말이죠.

보다 못한 사장이 배분을 해서 너는 주문을 받고 서빙을 하고 너는 음식을 만들어라 너는 설겆이를 해라 이런식으로 분배를 해서 작업을 하는게 멀티스레딩방식입니다.

그런데 JS는 단일 스레드방식을 사용하고 있습니다. 즉, 똘똘한 1명이 주문도 받고 음식도 만들고 설겆이도 다하는 슈퍼맨이라는 것이죠.

슈퍼맨의 시간을 어떻게 알뜰하게 사용할 수 있을까 해서 나온 것이 비동기 방식입니다. 손님이 오기까지 메뉴판을 들고 대기하는게 아니라 손님이 오면 어서오세요 하면서 메뉴판을 가져다 주는 방식인것이죠.

슈퍼맨의 시간을 알뜰하게 쓰면서 주문받고 음식만들고 서빙하도록 순차적으로 할 수 있도록 JS에서 지원하는 세 가지의 방식을 알아보겠습니다.

타입스크립트인데 왜 JS 얘기를 하느냐는 당연히 타입스크립트가 JS기반이기 때문입니다.

callback

콜백방식은 받고 나면 해당 콜백을 실행해주는 방식입니다. 앞의 함수가 실행되면 파라미터로 받은 다음 함수가 실행되는 방식이죠.

1
2
3
손님왔다('어서오세요!', function (){
주문을 받는다();
}

이러한 함수가 있다면 손님왔다() 함수가 실행 된 후 주문을 받는다() 함수가 실행되게 함수를 작성합니다. 그러면 손님이 오면 -> 주문을 받는다()가 되는거죠. 손님이 없을때 주문을 받지 않아도 됩니다.

그런데 콜백을 너무 많이 작성하면 알아보기가 힘들어집니다.

전체적인 식당로직을 작성해 본다면 이런식이 되겠죠.

1
2
3
4
5
6
7
8
9
10
11
일을한다('인사', function () {
일을한다('메뉴판가져다주기', function () {
일을한다('주문받기', function () {
일을한다('요리', function () {
일을한다('서빙', function () {

});
});
});
});
});

로직이 여러 단계로 분리되어있어 콜백을 작성하다보니 계단형식의 callback hell이 만들어 졌습니다.

그렇다고 하나의 함수로 모으는 행위는 OOP의 원칙에 좋지 않은 행동이고요.

그래서 좀 더 쉽게 쓰는 방법이 등장했습니다.

promise

ES6에서 서드파티로 지원되었던 프로미스가 공식적으로 지원되기 시작하였습니다.

can i use promise?

조금 더 쉽게 만들어줍니다.

사용방식은 promise.then(할일).catch(오류시할일)로 정의됩니다.

위의 코드를 바꿔보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
일을한다().then(
인사하기
).then(
메뉴판가져다주기
).then(
주문받기
).then(
요리
).then(
서빙
).catch(
고객, 아직도 문제있어요?
)

똑같은 인사하기 ~ 서빙까지 진행하는데 1열로 보니까 좀 더 쉽게 표현이 됩니다.

근데 .then이 체인처럼 길게 주르르륵 늘어지게 보이는것도 마음에 안드네요.

그래서 좀 더 단순하게 바꾸는 방법을 정의했습니다.

자세한 문법은 따로 검색해보시길 바랍니다.

async/await

async/await 방식은 좀 더 간단하게 표현할 수 있도록 도와주는 방식입니다.

함수에 async만 달아주고 각각 일(함수)마다 await만 달아주면 마치 위에서 부터 차례대로 실행되는 명령형 프로그래밍 마냥 실행할 수 도와줍니다.

can i use async/await?

사용법은 걍 await 할일()이면 끝납니다.

1
2
3
4
5
6
7
8
9
10
11
async 일을한다(){
try {
await 인사하기();
await 메뉴판가져다주기();
await 주문받기();
await 요리();
await 서빙();
} catch(문제생김) {
고객, 뭐가불만이예요?
}
}

try~catch안의 함수만 보시면 훨씬 간단해지고 보기 쉬워진것을 알 수 있습니다. 보시면 인사하기 부터 서빙까지 일직선으로 표현만 하면 됩니다.

단, 주의할 점이 조금 있습니다만 오류를 검출하려면 try~catch 문을 사용해야하며 async 함수를 외부에서 호출해줘야합니다.

그리고 async도 내부적으로는 프로미스를 사용하기 때문에 프로미스 문법을 사용해야 합니다. then() 이런것 말이죠.

마무리

타입스크립트는 최신 함수를 전부 지원합니다. 골라서 사용합시다..

내가 promise/async,await를 이용해 짱짱맨을 만들어 내갰어 라고 생각해도 IE11 때문에 어차피 쓰기 힘들어요 ㅎㅎ