오늘은 JS의 비동기에 관해 설명해 보고자 한다. JS에 대해 잘 모르고 비동기에 대한 개념이 희박하던 때, 단순히 콜백함수가 비동기 함수인 줄 알았다. 하지만 단순히 콜백함수를 만든다고 해서 비동기적으로 작동하는 것은 아니다. 특정 조건의 함수만 비동기 함수가 될 수 있다.
동기와 비동기 작업에 대해 알아보고 싶다면 해당게시글을 참고하자.
조금 더 자세히 알아보자.
콜백 함수는 동기이다.
const count = (num, callback) => {
for (let i = 0; i < 10; i++){
console.log(num)
num += 1
}
callback(num)
}
count(1, (num) =>{
console.log(1, num)
})
console.log("============================")
count(1000, (num) => {
console.log(1000, num)
})
count 함수는 파라미터 num에 10번 반복문을 돌면서 1을 더하는 함수이다. 그리고 for가 끝나면 콜백을 실행한다.
해당 코드를 실행하면 아래와 같은 결과가 나온다.
1
2
3
4
5
6
7
8
9
10
1 11
============================
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1000 1010
완벽하게 동기로 실행되는 것을 볼 수 있다. 그러므로 콜백함수를 만든다고 해서 비동기로 작동하지 않는다.
javascript 런타임
js에서 비동기를 이해하기 위해서는 javacript 런타임
에 대해 이해할 필요가 있다.
런타임은 어떠한 코드가 실제로 구동할 수 있는 환경을 의미힌다. 그러므로 당연하게도 javascript 런타임
은 js 코드를 실제로 구동할 수 있는 환경이다.
javascript 런타임
도 종류가 있는데, 크게 분리하면 웹 브라우저
와 node.js
가 있다. 웹 브라우저는 흔히 사용하는 크롬, 사파리, 파이어폭스 등이 있다.
앞서 런타임은 구동 환경을 의미한다고 했다. javascript 런타임
에는 어떤 종류의 환경이 존재할까?
javacript 엔진
이벤트 루프
포함
Web APIs
(node.js에서는libuv
)
이 두가지가 존재한다.
javascript 엔진
그렇다면 javascript 엔진
이란 무엇일까? js 코드를 실제로 실행하는 영역이다. 개발자가 작성한 모든 js 코드는 javascript 엔진
에서 파싱되고 실행된다. 이 javascript 엔진
은 싱글 스레드에서 작동한다.
여기에는 흔히 알려져 있는 이벤트 루프
도 포함되어 있다. 이벤트 루프
에 대해서는 뒤에서 자세하게 설명하도록 하겠다. 우선 이 이벤트 루프
가 javascript 엔진
에서 작동한다는 사실만 기억하자.
javascript 엔진의 구성 요소
- 콜 스택 (call stack)
실행되어야할 함수들을 저장하는 곳
const test = (num) => { console.log(num) } test(1)
test(1)
이 이 콜스택에 삽입 후 실행test(1)
에 있는console.log(1)
을 콜스택에 삽입 후 실행- 1이 출력 후
console.log(1)
콜스택에서 제거 test(1)
콜스택에서 제거
- 힙 (heap)
- 데이터가 동적으로 저장되는 공간
- 이벤트 루프(event loop)
- 비동기 작업이 끝난 후 결과값을 처리할 콜백 함수를 저장해두는 곳
Web APIs
웹 브라우저
에서 비동기적인 이벤트를 처리하기 위해 제공하는 API들이다. 웹 브라우저
에서 제공하는 것이기 때문에, 해당 api는 javascript 엔진
에서 실행되지 않는다. 이 api들은 javascript 엔진
과 실제로 다른 프로세스에서 실행되며, js에서 호출할 수 있도록 javascript 엔진
에서는 인터페이스만 제공한다.
여기서 잠깐! 인터페이스만 제공한다는 것의 의미란?
API는 Application Programming Interface의 약자이다. 이는 두 개의 서로 다른 프로세스(혹은 프로그램)간에 통신을 위한 일종의 약속이다.
A
와B
라는 두 개의 프로세스가 있고,B
에는getData
라는 기능이 있다.A
에서B
의getData
라는 기능을 사용하기 위해서는getData
의 실행에 필요한 데이터를 전달해 주어야 한다. 이때 "B
는 특정 형태의 프로토콜과 특정 형태의 구조로 데이터를 전달해주면,getData
라는 기능을 실행하고, 결과를 특정한 형태로 응답해주겠다" 라고 약속하는 것이 바로 API라고 할 수 있다.
Web APIs
도 똑같다. 실제 Web APIs
는 js 코드로 실행하면, javascript 엔진
이 해당 요청을 다른 프로세스(=웹 브라우저)에게 요청하고, 응답을 받으면 그것을 js에서 사용할 수 있도록 결과값을 반환해주는 역할을 한다.
즉, javascript 엔진
과 웹 브라우저
간의 통신 약속이 바로 Web APIs
이다.
해당 게시글을 처음 시작할 때, 특정 조건의 함수만 비동기가 될 수 있다고 했다. 그 특정 조건의 함수란 바로, Web APIs
에 등록된 함수이다.
이벤트 루프
이벤트 루프를 이해하기 위해서는 비동기에 대한 이해가 필요하다.
비동기란? 파일 저장, 네트워크 요청 등 처리에 시간이 걸리는 I/O 작업이 진행 중에 다른 코드를 실행하는 것을 의미한다. 시간이 걸리는 작업 중에는 프로그램은 놀고 있는 것이기 때문에, 이 시간을 최대한 활용하기 위해 나온 개념이다.
js는 싱글 스레드이기 때문에, 비동기 코드를 실행할 수 없다. 그래서 앞서 설명한 Web APIs
를 통해 브라우저에게 비동기 작업을 요청한다. 그렇다면, 비동기 작업이 종료되었을때, 응답을 받을 것이다. 그 응답은 어떻게 처리해야 할까?
setTimeout(()=>{console.log(1)}, 1000)
console.log(2)
/*
결과
2
1
*/
위와 같은 코드를 보자. 해당 코드는 실행하면 2가 출력되고 1초 후 1이 출력될 것이다. 조금 이상하지 않은가? 코드는 위에서 아래로 진행하면서 실행될 텐데, 1, 2가 출력되는 것이 아니라 2, 1로 반대로 출력된다. 마치 이것은 두 번째 줄이 먼저 실행되고, 첫 번째 줄이 실행된 것 처럼 보인다.
이것이 앞서 설명한 응답 처리에 대한 질문의 답이라고 할 수 있다. 코드 실행을 순서대로 알아보자
setTimeout
콜스택에 삽입 후 실행- 1초 타이머를
Web API
를 통해웹 브라우저
에게 요청, 이때()=>{console.log(1)}
을 같이웹 브라우저에게 전달
setTimeout
콜스택에서 제거console.log(2)
콜스택에 삽입 후 실행- 2 출력
console.log(2)
콜스택에서 제거- 1초가 지난 후
웹 브라우저
는()=>{console.log(1)}
을이벤트 루프
큐에 삽입 이벤트 루프
는 큐에()=>{console.log(1)}
가 생겼으므로, 해당 함수를 콜스택에 삽입()=>{console.log(1)}
실행console.log(1)
콜스택에 삽입 후 실행- 1 출력
console.log(1)
콜스택에서 제거()=>{console.log(1)}
콜스택에서 제거- 종료
이렇듯, 코드는 순차적으로 실행된 것이 맞고, 응답 처리의 방법은 비동기 작업이 종료된 이후 처리할 코드를 미리 넘겨주는 것이다. 이것이 바로 콜백 함수
이다. 위 예제에서 콜백 함수는 ()=>{console.log(1)}
이다.
그리고 이벤트 루프의 역할은 비동기 처리가 완료된 이후 실행되어야 할 콜백 함수들의 저장소이다. 이 이벤트 루프는 콜백 함수를 저장하고, 일정 주기(틱)마다 콜백 함수 큐를 확인해서 콜백 함수가 존재하면 해당 함수를 콜 스택에 삽입한다.
아래 GIF를 보면 콜 스택
, 웹 브라우저
, 이벤트 루프
간의 상호작용을 한눈에 볼 수 있다.
정리
- 콜백을 사용한다고 모두 비동기가 되는 것이 아니다.
javascript 런타임
은 js를 실행하는 구동 환경이다.javascript 엔진
과Web APIs
로 구성된다.
javascript 엔진
은 js를 파싱하고 실행한다.- 싱글 스레드로 작동한다.
- 여기서는 비동기가 작동할 수 없다.
콜 스택
,힙
,이벤트 루프
로 구성된다.
Web APIs
는웹 브라우저
에서 비동기 이벤트를 처리하기 위해 제공되는 api이다.javascript 엔진
은 비동기 요청을Web APIs
를 통해웹 브라우저
에게 전달한다.웹 브라우저
는 비동기 작업이 끝나면 콜백 함수를이벤트 루프
콜백 함수 큐에 삽입힌다.
콜백 함수
란 비동기 요청이 끝난 후 응답을 처리하는 함수이다.이벤트 루프
란 콜백 함수 저장소이다.일정 주기(틱)
마다 콜백 함수 큐를 검사하고, 콜백 함수가 존재하면 콜 스택에 해당 함수를 삽입한다.