함수의 비동기화

기존 async await 를 단순히 비동기를 순차적으로 처리하는 데에만 이용하다가,
실무상 비동기로 함수를 처리해야 할 일이 생겼다.

일반적인 자바스크립트 함수

1
2
3
function (){
//그냥 함수
}

자바스크립트 특성상 비동기 함수의 경우 일반 함수에서 호출 시 실행하라는 오더만 내리고 바로 다음 항목을 진행한다.

비동기를 동기적으로 처리할 때, async await 의 사용법.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function somePromiseFunc(){ //Promise 반환 함수인 somePromiseFunc.
return new Promise((resolve,reject)=>{
try{
//input do something..
resolve(async_logic_result)
}catch(err){
reject(err)
}
})
}

async function(){ //async await 의 일반적인 사용.
let result = await somePromiseFunc() //비동기 함수의 응답을 받기 위해 await를 사용
//do other func
return result;
}

async await 는 비동기 처리함수를 동기적으로 처리할 때 쓰이는 문법이다.
await는 async를 선언한 함수 내부에서만 쓸 수 있으며, Promise 를 반환하는 함수에 써서 result 변수에 resolve 내부에 들어가있는 결과값을 받을 수 있다.

평소에 이렇게 비동기를 동기적으로 수행처리하는 과정만 생각하는게 주인데, 이번에는 업무상 응답속도를 줄이기 위해 의도적으로 함수를 비동기화해야하는 것이었다.

실무에선 300줄 이상의 무거운 쿼리는 수행하라는 명령만 내리고, 문자열처럼 생성이 빠른 것들은 빨리 생성해서 바로 200 응답을 전송하길 원했다.

이 방법을 찾는 과정에서 각 실행 방법의 응답속도를 비교했고, 더불어
async-await 키워드의 새로운 기능을 알게 되었다.


속도 비교

1. 일반 실행

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function someHeavyFunc(){
//무거운 쿼리 로직. query를 때릴 때 사용하는 모듈 자체는 비동기식으로 작동한다.
}

function callAsyncFunc(){

let fast_key = otherModule.keyMaker(someInput); //빠른 실행이 가능한 함수

someHeavyFunc()

let fast_answer={
key:fast_key
}

return fast_answer
}

javascript는 기본적으로 비동기로 작동한다고 하지 않았었나..? 하지만 Postman과 console.log로 각 함수 실행과정과 응답속도를 테스트한 결과, 200 응답 뒤에 무거운 함수가 실행되는 경우는 없었다.

default_do
거진.. 요청당 약 1초가 걸린다. 어마무시하다.

2. setTimeout 함수

두 번째로는 비동기 함수의 개념을 배울 때 주로 사용하는 setTimeout으로 테스트하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function someHeavyFunc(){
//무거운 쿼리 로직..
}
function callAsyncFunc(){

let fast_key = otherModule.keyMaker(someInput); //빠른 실행이 가능한 함수

setTimeout(function(){
someHeavyFunc()
},50) //비동기 처리를 위해서는 어쩔 수 없나...? 근데 진짜 이렇게?

let fast_answer={
key:fast_key
}

return fast_answer
}

async 키워드를 함수 앞에 붙인다는 게 무슨 뜻인지 제대로 알지 못해서 생긴 폐해다(…)

settimeout_do
응답속도가 많이 줄었다. setTimeOut 함수가 비동기 함수인 걸 알고 return을 먼저 보내고 무거운 함수를 실행한 것이다. 속도 개선은 되었지만, 당연스럽게도 setTimeOut함수를 사용하면 초반지연이 발생한다.

앞서 실험했던 일반 실행과 비교해봤을 때, 이는 js가 봤을 때 함수가 비동기임을 몰라서 생기는 상황인 것 같았다.

  • 그러면 어떻게 비동기 함수인걸 알려줘야할까?

답은 async-await 페어 중 async에 있었다.

3. async 키워드

async 키워드는 함수를 비동기 취급한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
async function someHeavyFunc(){
//무거운 쿼리 로직..
}
function callAsyncFunc(){

let fast_key = otherModule.keyMaker(someInput); //빠른 실행이 가능한 함수

someHeavyFunc()

let fast_answer={
key:fast_key
}

return fast_answer
}

무거운 함수 앞에 async를 붙이고, 무거운 함수를 호출하는 함수는 async 키워드를 붙이지 않는다.
async 키워드를 붙이지 않았으니, await도 쓸 수 없다.
결과는 어떨까?

async_do

성공이다! 원하는 응답도 제대로 가져온다.

응용

… 그러면 특정 부분은 비동기로 수행하고 비동기 함수끼리는 동기적으로 처리하고 싶을 때, 이렇게 하면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
function caller(){ //caller는 일반 함수

let faster = doMakeFaster() //일반 함수

async function doAsync(){ //비동기로 묶어서 처리할 랩퍼를 선언
let result1= await someAsyncFunc() //비동기 함수를 순차적으로 시행
await someAsyncFunc2(result1) //비동기 함수를 순차적으로 시행
}

doAsync() //비동기로 시행

return faster;
}

faster 먼저 변수에 결과값이 담기고, doAsync()는 명령만 내린 뒤 바로 return 값을 반환한다. 이후 doAsync() 함수 수행 명령을 내린 시점에서 someAsyncFunc()와 someAsyncFunc2가 순차적으로 실행된다.

비동기 처리를 동기적으로 수행하기 위해 여태껏 await에만 초점을 맞추고 있었는데, 이번엔 await를 사용하지 않고 async만 사용해 보았다.
async-await는 기본적으로 페어지만, 함수를 비동기로 실행할 때도 있는 법이다.
두 키워드를 좀더 제대로 알게 된 것 같아 기쁘다. 유익한 경험이었다.