자바스크립트로 알아보는 동기/비동기, 블록킹/논블록킹
정의
각각의 정의를 핵심만 요약하면 다음과 같다.
- Block - 함수를 호출했을 함수의 모든 행위가 끝난 후에 제어권을 넘겨준다.
- Non block - 함수를 호출하면 함수의 종료와 상관없이 바로 제어권을 넘겨준다.
- Sync - 작업을 순차적으로 처리한다.
- Async - 작업을 순차적으로 처리하지 않는다.
Example Code
개념만 읽어서는 정확히 이해하기가 어렵다. 각각의 방식을 조합한 4가지방식에 대해 코드로 알아보자
- Blocking + Sync : 제어권을 끝날 때까지 안넘겨줌 + 순차적으로 실행
1 | const sum1 = n => { |
위 코드는 숫자 n을 받아 합계를 구하는 간단한 함수다. 이 함수 블록킹이자 동기 함수이다.
확인하기 위해서 다음을 실행해보자.
1 | console.log(sum1(1e9)); |
큰숫자를 인자로 넣어서 실행해보면 sum1 함수가 끝날 때까지 콘솔이 ‘B’가 찍히지 않고 완료되고나서 찍힌다.
끝날 떄까지 제어권이 아래로 넘어가지 않기 때문에 블록킹함수인 것을 확인할 수 있다.
또한 순차적으로 실행되기 때문에 당연히 동기방식이다.
- Blocking + Async : 순차적으로 실행할 필요가 없지만 + 제어권이 안넘어와서 결국 순차적으로 실행됨
1 | const sum2 = (n, fn) => { |
자바스크립트에서 비동기 함수를 만드는 방법중 하나는 callback 함수를 이용하는 것이다.
A행위와 B행위에 인과관계가 있을 때 순서에 상관없이 실행할 수 있는 방법은 B가 A와 인과관계가 있는 순차적인 동작을 A에게 위임(callback)하는 것이다.
B는 그래서 A와 상관없이 동작할 수 있지만, A함수 자체가 블록킹함수라서 결국에는 막혀 순차적으로 실행되게 된다. 결국 비동기의 의미가 없어진다 ㅠㅠ
Blocking + Async는 안티패턴이다
- Non Blocking + Sync : 제어권이 바로 넘어가지만 + 순차적으로 실행하기 위해 계속 모니터링함
그렇다면 자바스크립트에서 논블로킹 함수는 어떻게 만들 수 있을까?
여러가지 방법이 있지만 가장 간단한 방법은 Web API에서 제공하는 setTimeout 함수를 사용하는 것이다.
Web API 같은 경우에는 Main UI 스레드와 다른 스레드에서 실행되기 때문에 제어권을 바로 넘겨줄 수 있다.
1 | setTimeout(() => console.log('A'), 1000); |
실제로 위 코드를 실행하면 ‘B’가 먼저 출력되는걸 볼 수 있다. 바로 제어권이 넘어오므로 논블록킹 함수이다.
setTimeout을 이용하여 sum1 함수를 논블로킹 + 동기 함수로 만들면 다음과 같다.
1 | const sum3 = n => { |
함수가 실행되고 결과값을 바로 리턴한다. 일정시간이 지나고 result.isComplete 이 true가 됐을 때
연산값이 result에 입력될 것이다. 자바의 Future와 비슷하다 ^^
위 함수를 실행하여 콘솔에 찍어보자
1 | let future = sum3(1e9); |
실제 연산이 끝나기 전에는 undefined가 출력된다. 인과관계가 있어서 순차적으로 실행해야 한다면(동기) 다음과 같이 계속 작업이 끝났는지 모니터링 해줘야한다.
1 | const id = setInterval(() => { |
계속 물어봐야됨 ㅎㅎㅎ
- Non Blocking + Async : 제어권을 바로 넘겨줌 + 콜백 함수를 주어서 자기일만 하면되므로 모니터링이 필요없다
1 | const sum4 = (n, fn) => { |
실행해보면 ‘B’가 먼저 출력되는걸 볼 수 있다.
Quiz
이쯤에서 퀴즈~ 프론트웹에서 자주쓰는 jquery Ajax 함수는 어떤 방식으로 동작할까요?
1 | const a = $.ajax("url").done(function(data) { |
정답은 …
제어권이 바로 b로 넘어가고, b와 순서상관없이 콜백(done)으로 처리하므로 비동기+논블락 입니다. ㅎㅎ