1. 비동기적 처리란?
대부분의 함수는 동기적으로 처리된다. 동기적이란 어떤 기능을 실행하고, 그다음의 기능을 실행한다는 의미다. 이건 마치 같은 라인에 선 계주와 같다. 한 선수가 목표한 거리를 다 지나야지만 바통을 넘겨받은 선수가 달릴 수 있다. 대부분의 기능은 이렇게 실현된다.
그런데, 만약에 너무 오래 걸리는 작업이 있다면? 예를 들어 우리가 유튜브를 본다고 하자. 유튜브에서 동영상을 불러들이는 시간은 다른 메뉴바를 불러들이는 시간보다 오래 걸린다. 그런데, 만약 동영상을 불러들이고 나서 다른 기능이 구현된다고 하면 사용자는 아무것도 없는 브라우저의 로딩이 끝나기만을 기다려야 할 것이다. 그러면 사용자들에게 불편을 주고 웹 애플리케이션에 안 좋은 인상만 남길 것이다. 그렇다면, 반대로 동영상을 모든 기능이 구현된 다음에 불러들인다면? 동영상을 보는 건 유튜브의 주된 기능인데 가뜩이나 가장 오래 걸리는 걸 가장 마지막에 구현한다? 말도 안 되는 소리다. 이를 방지하기 위해 "비동기적 처리"를 해준다
그렇다면 비동기적 처리는 어떤 것인가? 같은 라인에서의 계주가 아니라 8라인 모든 선수의 달리기 시합이라고 생각해보자. 전체 시합은 가장 느리게 도착하는 주자가 골인 지점에 도착하기 전까지 끝나지 않는다. 다만, 가장 느리게 도착하는 선수가 아닌 다른 선수들은 그 시합이 끝나기 전에 이미 골인 지점을 통과했다. 이런 게 비동기적 처리다. 다시 말해 모든 기능 구현을 동시에 실행시켜서 가장 빨리 기능이 끝난 건 바로 보일 수 있도록 작업을 해놓는다. 우리가 유튜브를 볼 때 동영상 로딩은 늦게 되지만 다른 기능들은 먼저 구현돼서 우리의 눈앞에 보이는 것이 바로 그 예시다.
비동기적 처리는 보통 Ajax Web API 를 요청할 때, 크기가 큰 파일을 읽을 때, 암호화/복호화 과정을 거칠 때, 작업 예약을 걸어 놓는 등의 일을 할 때 비동기적 처리를 한다.
비동기 작업에 앞서 동기적 처리로 코드를 작성해보자. 현재 JE 카페에서는 콜드 브루는 금방 만들 수 있는데 아메리카노는 조금 시간 걸리는 이상하고 기묘한 상황에 처해있다. 심지어 JE 카페는 동기적으로 일처리를 하는 카페다. 이 말은 손님이 두 명 있는데, 앞선 손님의 주문을 받고 그 손님의 음료를 제공한 다음에 뒤에 계신 손님의 주문을 받는 것이다. 벌써부터 카페가 망할 것 같은 냄새가 난다. 하지만, 이렇게 일처리를 한다고 가정했을 때의 코드를 작성하면 다음과 같다.
const americano = () => {
for (let i = 0 ; i < 3000000000 ; i++) {}
console.log('아메리카노 나왔습니다.')
}
// 3000000000번을 센 후에 아메리카노 콘솔창이 찍힌다.
const coldBrew = () => {
for (let i = 0 ; i < 50000 ; i++) {}
console.log('콜드브루 나왔습니다!')
}
orderAmericano()
americano()
orderColdBrew()
coldBrew()
이걸 콘솔창에 찍으면 다음과 같다.
아메리카노 주문을 받고 아메리카노 나오고 뒤의 손님 콜드 브루를 주문받고 잽싸게 콜드 브루를 내놓는다. 직관적으로 느낀다면 일단 주문을 둘 다 받고 콜드 브루를 먼저 손님에게 준 다음 아메리카노를 주는 게 정상일 것 같다. 아메리카노 받는 사람은 기분이 나쁠진 몰라도 이렇게 만드는 시간이 다른 건 어쩔 수 없다. 카페 사장인 JE는 곧 망할 것 같은 조짐이 보여 비동기적으로 일처리 하기로 한다. 비동기의 대표적인 예시인 타이머 함수(타이머 API)를 사용하면 다음과 같이 된다.
const americano = () => {
setTimeout(() => {
for (let i = 0 ; i < 3000000000 ; i++) {}
console.log('아메리카노 나왔습니다!')
}, 100)
}
// setTimeout 은 밑에서 자세히 배울 거긴한데, 100ms 후에 함수를 실행하는 것
const coldBrew = () => {
for (let i = 0 ; i < 1000000000 ; i++) {}
console.log('콜드브루 나왔습니다!')
}
orderAmericano()
americano()
orderColdBrew()
coldBrew()
이걸 콘솔창에 찍으면 다음과 같다.
작업이 오래 걸리는 함수를 실행할 때, 그 함수를 제외한 빠르게 실행될 수 있는 함수들이 있기에 함수 실행 시점을 똑같은 시간에 잡아서 빠르게 구현될 수 있는 건 빠르게 구현하고(콜드 브루 커피는 빨리 내놓아버리고) 작업 시간이 오래 걸리는 건 일단 실행해놓고 늦게나마 구현할 수 있도록 하는 것이다(아메리카노는 그다음에 내놓기)
2. Timer 함수(Timer API)
비동기의 대표가 Timer 함수(Timer API) 다. 우리가 API라고 해주는 이유는 이 함수 실현이 자바 스크립트 내부에서 이뤄지는 것이 아니라 몇 초 뒤에 실행시켜달라고 브라우저에 요청하는 것이기 때문이다.
1) setTimeout (함수, 시간) , clearTimeout( )
setTimeout 안에 있는 함수는 두 번째 인자로 받은 시간 뒤에 실행된다. 이때, 시간의 단위는 ms(밀리세컨드)다. 반대로 clearTimeout 을 사용하면, 설정된 setTimeout 함수를 종료시킨다. 매개변수로는 실행시키지 않을 setTimeout 함수명을 가져온다.
예를 들어 DOM에 <button>실행하지마!</button> 태그를 하나 만들었다고 가정해보자.
const setTime = setTimeout( () => {
console.log('JE!')
}, 2000) // 1s === 1000ms
const elButton = document.querySelector('button')
elButton.addEventListener('click', () => {
clearTimeout(setTime)
})
이 코드를 분석해보면, 좋든 싫든 setTimeout 함수가 2초 뒤에 'JE'를 console 창에 찍는다. 하지만, 만약 우리가 그 2초 안에 button 을 누르면 setTime 함수는 작동하지 않는다.
2) setInterval (함수, 시간), clearInterval( )
setInterval 안에 있는 함수는 시간 간격마다 실행된다. setTimeout 이 시간이 되면 함수가 실행되는 거라면 setInterval은 함수가 실행되면 시간은 리셋되고 다시 그 시간이 될 때 함수를 더 실행한다. clearInterval 은 매개변수로 들어온 setInterval 함수를 중지시킨다. 마찬가지로 똑같은 button이 있고 함수만 바꿔보자.
const setInt = setInterval( () => {
console.log('JE!')
}, 500) // 시간은 ms. 1s === 1000ms
const elButton = document.querySelector('button')
elButton.addEventListener('click', () => {
clearInterval(setInt)
})
코드를 분석하면, 0.5초마다 console창에 JE! 가 표시되고, button을 누르면 멈출 것이다.
다음 시간부터는 ES6 이후 비동기를 실현하기 위한 Promise 라는 클래스를 배워보도록 하자.
'패캠 인강 > Vanilla JavaScript' 카테고리의 다른 글
[패캠 인강] 비동기적 처리 (Promise) (0) | 2021.09.10 |
---|---|
[패캠 인강] 단축 평가 논리 계산법(Truthy, Falsy) (1) | 2021.08.29 |
[패캠 인강] 배열과 배열 내장함수 (3) (0) | 2021.07.30 |
[패캠 인강] 배열과 배열 내장함수 (2) (0) | 2021.07.25 |
[패캠 인강] 배열과 배열 내장함수 (1) (0) | 2021.07.22 |