개발

[Javascript]자바스크립트-동기, 비동기와 스크립트 엔진 (1)

dev.lecky 2022. 8. 23. 13:49

자바스크립트 코드의 실행순서와 기본개념에 대해 알아보겠습니다.

 

1. 자바스크립트의 기본개념

2. JS Engine(자바스크립트 엔진)

 

 

2022.08.23 - [개발] - [Javascript]자바스크립트-동기, 비동기와 스크립트 엔진 (1)

2022.09.03 - [개발] - [Javascript]자바스크립트-비동기 promise 객체 (2)


 

자바스크립트의 기본개념

 

자바스크립트는 기본적으로 싱글 쓰레드이며 비동기로 동작하고 있습니다.

 

  만약, 싱글 쓰레드 방식을 이용하면서 비동기가 아닌 동기적 작업방식 이라면, 전체적인 실행시간이 크게 증가하게 될 것입니다.(하나의 작업이 끝나야지만 다른 작업을 시작할 수 있기 때문).

 

  자바스크립트는 웹 브라우저에서 사용자의 사용성과 편의를 위해 시작된 언어라는 점에서, 전체적인 동작시간이 길어지게 된다면 사용성이 떨어지게 되는 치명적인 문제가 발생합니다. 이를 극복하기 위해 자바스크립트는 하나의 작업이 종료되기 전에, 다른 작업을 동시에 실행시키는 논 블로킹 방식으로 동작합니다.

 

비동기 처리방식 - 논 블로킹 방식

 

  비동기 방식은 여러개의 작업이 동시에 진행되기 때문에, 하나의 작업이 종료되면 다른 작업을 시작하는 동기방식에 비해서 각각 작업의 진행과정을 확인하는 과정이 필요합니다. 이를 위해 콜백함수를 붙여서 전달합니다. 콜백함수가 실행되면 결과값을 확인하거나 동작이 끝났다고 판단할 수 있습니다.

 

//내장 비동기함수 setTimeout
setTimeout(arg1, arg2)
arg1: 콜백함수. 딜레이타임이 지난 이후 실행하는 함수
arg2: 딜레이타임(ms, 1000ms -> 1초)

//예시
setTimeout(()=>{
  console.log("2초 후 출력");
  }, 2000);

 


Javascript Engine - 자바스크립트 엔진의 동작

 

JS engine은 Heap과 Call Stack 영역으로 구성되어있습니다.

  • Heap: 변수나 상수의 메모리를 저장하는 영역
  • Call Stack: 코드의 실행에 따라서 호출 스택을 쌓는 영역

 

동기코드 작동순서

1.  동기코드 작동순서

 

Main Context: 자바스크립트 최상위 문맥. 자바스크립트 코드 실행순간에 call stack에 들어오고, 프로그램이 종료되는 순간에 나간다.

 

  위 사진에서 보면, three() 함수가 가장 먼저 실행되고, three() 내부 two()함수 실행, two() 내부 one() 함수가 실행되게 되며

Call Stack에 실행순서대로 Main Context 위에 쌓이게 됩니다. 마지막으로 실행된 one() 함수는 내부에 함수가 더이상 없으므로 1을 리턴한 이후 Call Stack에서 빠져나갑니다. 

 

동기코드는 이렇게 함수의 실행순서에 따라 순차적으로 Call Stack에 쌓여서 최근에 들어온걸 먼저 실행시키는 순서로 실행됩니다.

 

 

2. 비동기코드 작동순서

  자바스크립트의 내장 비동기함수 setTimeout을 통해 비동기코드 작동순서를 확인해보겠습니다.

비동기코드 작동순서

 

  비동기함수인 setTimeout()의 경우, 실행이 끝날 때 까지 기다리지 않고, 해당 함수를 Web APIs로 전달합니다. 이후 Call Stack에서는 남아있는 함수를 실행하고, web APIs에서는 setTimeout()의 실행시간이 흘러갑니다. 

 

 

  위 사진을 보면 Web APIs에서는 setTimeout의 시간이 다 지나가게 되면 콜백함수인 cb() 함수가 Callback Queue로 옮겨지게 됩니다. Call Stack 에서는 비동기로 남아있는 함수들을 계속해서 실행하고 있습니다. 이후 Call Stack에 남아있는 함수가 더 이상 없을 시, Event Loop가 동작합니다.

Event Loop: Call Stack에 Main Context를 제외한 다른 함수가 남아있는지 확인한 이후, 다른 함수가 남아있지 않은 상태라면, (콜백함수를 실행 할 수 있는 상태라고 판단하고) Callback queue에서 Call Stack으로 콜백함수를 전달한다.

 

 

  Event Loop에 의해 Callback Queue에 의해 cb()함수(setTimeout의 콜백함수)가 Call Stack으로 이동

-> cb() 함수 실행 -> callstack에서 제거

이러한 순서로 비동기함수가 동작합니다.

 

**비동기코드의 단점

  앞서 본것 처럼 비동기코드를 콜백함수의 형태로 전달하면 함수의 실행과정과 결과를 확인할 수 있지만, 콜백함수가 많이 중첩될수록 코드의 구조가 복잡해지는 단점이 존재합니다.

// Callback 지옥
taskA(1,2,(a_res) => {
  console.log("task A :", a_res);
  taskB(a_res, (b_res) => {
    console.log("task B :", b_res);
    taskC(b_res, (c_res) => {
      console.log("task C :", c_res);
    });
  });
});

 

위 코드와 같이 callback이 많이 중첩될수록 가독성이 떨어지고 코드를 수정하기에도 많은 노력이 필요합니다.

 

이를 해결하기 위해  Promise  객체가 등장했는데, 이는 다음장에 이어서 포스팅하도록 하겠습니다.

 

 

2022.08.23 - [개발] - [Javascript]자바스크립트-동기, 비동기와 스크립트 엔진 (1)

2022.09.03 - [개발] - [Javascript]자바스크립트-비동기 promise 객체 (2)