본문 바로가기

Javascript

JavaScript - 비동기와 동기 (Asynchronous and Synchronous)

자바스크립트의 비동기와 동기에 대해서 알아보자.

 

동기적 실행 (synchronous) 이란 동시에 일어난다는 이야기이다. 요청과 그 결과가 동시에 일어난다는 일종의 약속이다. 요청을 하면 시간이 얼마가 걸리던, 요청한 자리에서 결과가 주어져야 한다. 즉,

  • 요청과 결과가 한 자리에서 동시에 일어난다.
  • A 노드와 B 노드 사이의 작업 처리 단위 (transaction) 를 동시에 맞춘다.

반면 비동기적 실행 (Asynchronous) 은 동시에 일어나지 않는다를 의미한다. 즉 요청과 결과가 동시에 일어나지 않는다는 약속이다.

  • 요청한 그 자리에서 결과가 주어지지 않는다.
  • 노드 사이의 작업 처리 단위를 동시에 맞추지 않아도 된다.

각각에는 장단점이 있으며, 맞는 쓰임새가 있다. 먼저 동기방식은 설계가 간단하고 직관적이나, 결과가 주어질 때까지 아무것도 못하고 대기해야 한다. 그러나 비동기방식은 동기보다 복잡하지만, 결과가 주어지는데 시간이 걸리더라도 그 시간 동안 다른 작업을 할 수 있으므로, 자원을 효율적으로 사용할 수 있다는 장점이 있다.

 

말로는 뭐든 쉽다. 먼저 예제를 보자.

 

동기방식의 예

  1. A의 계좌에서 10000원을 뺄 예정이다.
  2. A의 계좌에서 B의 계좌로 10000원을 송금한다.
  3. B의 계좌에서 10000원을 받았다는 걸 인지하면, A의 계좌에 10000원을 받았다고 신호를 보낸다.
  4. 이로써 A와 B의 계좌에 각각 차감과 증가가 동시에 발생한다.

순서를 보면, 1~3의 과정이 모두 일어난 걸 서로 확인한 후에, 같은 일을 동시에 진행했다 (4번).

 

비동기방식의 예

  1. 학생이 시험문제를 푼다.
  2. 시험문제를 모두 푼 학생은 선생님에게 전송한다.
  3. 선생은 학생의 시험지를 채점한다.
  4. 채점이 다 된 시험지를 학생에게 전송한다.
  5. 학생은 선생이 전송한 시험지를 받아 결과를 확인한다.

학생과 선생은 시험지라는 연결고리가 있지만, 시험지에 행하는 행위가 서로 다르다. 서로의 목적이 다르기 때문에, 둘의 작업 처리 시간은 일치하지 않는다.

 

즉, 동기와 비동기는 어떤 작업 혹은 그와 연관된 작업의 처리에 대한 시각의 차이이다. 

 

동기적 실행

자바스크립트 코드에서 이게 어떻게 실행되는지 확인해보자. 먼저 sync_and_async.js 파일을 만들어서 아래와 같이 써보자.

 

function fakeSetTimeout(callback, delay){
    callback();
}

console.log(0);
fakeSetTimeout(function() {
    console.log('hello~');
}, 0);
console.log(1);

 

결과

 

PS C:\Users\bumsu\nodejs-projects\web1_html_internet\web1_html_internet> node sync_and_async.js
0     
hello~
1 

 

위 코드의 실행 과정은 다음과 같다. 스택은 후입선출 (last in first out, LIFO) 구조이다.

 

  1. 먼저 스택에서 sync_and_async.js 파일을 실행시킨다. 가장 먼저 실행시킬 console.log(0) 을 실행시킨다.

  2. console.log(0)이 실행되었으니 스택에서 제거하고, 다음 함수인 fakeSetTimeout 함수를 실행시킨다.

  3. fakeSetTimeout 함수에서 console.log('hello~') 함수를 실행시킨다.

  4. 함수가 실행되었으니 console.log('hello~')를 제거하고, fakeSetTimeout 도 제거한다. 그리고 마지막으로 console.log(1) 을 실행시킨다.

  5. 모든 함수의 실행이 완료되었으니 스택에서 sync_and_async 파일을 제거한다.

비동기적 실행

그렇다면 비동기적 실행에서는 이게 어떻게 실행될까? sync_and_async 파일을 다음과 같이 고쳐준 후 다시 실행해 보자.

 

console.log(0);
setTimeout(function() {
    console.log('hello~');
}, 0);
console.log(1);

 

결과

 

PS C:\Users\bumsu\nodejs-projects\web1_html_internet\web1_html_internet> node sync_and_async.js
0
1
hello~

 

아무리 setTimeout이 있다해도, delay를 0으로 놓았는데도 1이 콘솔에 먼저 찍히는 것을 볼 수 있다. 이는 왜 그럴까? 먼저 자바스크립트의 타이머에 대해서 알아보자. 자바스크립트의 타이머는 자바스크립트 밖에 있다. 내부가 아닌 브라우저의 웹 API 를 통해서 받아오는 것이다.

 

위 코드의 실행 방식은 다음과 같다. 스택과 반대로 큐는 선입선출 (first in first out, FIFO) 구조이다.

 

  1. 먼저 스택에 실행하는 프로그램과 console.log(0) 을 넣어주고 실행시킨다.

  2. 실행이 완료됐으니 제거해 주고, setTimeout 함수를 가져온다. setTimeout은 Promise를 만들어주고 실행이 완료된다. 이 Promise는 큐 (Queue) 에 콜백 함수로써 들어가게 된다.

  3. 마지막으로 console.log(1)을 실행시켜준다.

  4. 모든 함수의 실행이 완료되었으니 프로그램을 스택에서 제거한다.

  5. 프로미스 (Promise) 로써 기다리고 있던 콜백함수가 이제 호출되어 실행된다.

  6. console.log('hello~') 함수가 실행되었으니 콜백과 함께 스택에서 제거한다.

출처

https://private.tistory.com/24

https://opentutorials.org/course/3332/21132

https://www.youtube.com/watch?v=j0Viy3v97gY