자바스크립트 기초

고은찬·2021년 8월 5일
1

Javascript

목록 보기
2/3

자바스크립트 공부

1. 자바스크립트 역사

1) 탄생

자바스크립트는 1995년에 넷스케이프(Netscape)의 브렌던 아이크(Brendan Eich)에 의해 만들어졌다.

처음에는 모카(Mocha)라는 이름으로 개발되었으나, 그 후에 라이브스크립트(LiveScript), 최종적으로는 자바스크립트(JavaScript)라는 이름으로 변경되었다..




2. 자바스크립트 특징

1. 싱글 스레드 언어
싱글 스레드 언어란 하나의 힙 영역과 하나의 콜 스택을 가진다는 뜻이다.
하나의 콜 스택을 가진다는 말의 의미는 한번에 한가지 일 밖에 하지 못한다는 의미이다.
예를 들어 네트워크 요청을 한다면, 응답이 올 떄까지 다른 일은 하지 못하고 마냥 기다릴 수 밖에 없다. ( blocking 상태 : 콜 스택이 멈춘 상태 (무한정 대기) )


2. 객체 기반의 스크립트 언어


3. 동적이며, 인터프리어 언어(타입 명시할 필요가 없음->타입스크립트가 나옴)
인터프리어 언어는 컴파일 언어(자바)처럼 소스 파일을 컴파일하여 사용자가 실행할 수 있는 실행파일(.exe) 로 만드는 것이 아닌, 소스 코드를 바로 실행 할 수 있는 언어를 의미한다.
자바스크립트는 웹 브라우저에 포함된 자바스크립트 인터프리터가 소스 코드를 직접 해석하여 바로 실행해 준다.


4. 객체지향형과 함수형 프로그래밍 모두 표현할 수 있음

5. 자바스크립트 표준 (ECMAScript)
1996년에 넷스케이프(Netscape)는 자바스크립트를 국제 표준안으로 만들기 위해 ECMA(European Computer Manufacturers Association)에 제출한다.
그 결과 ECMA는 ECMAScript라는 새로운 표준을 제정하였고, 그 첫 번째 버전인 ECMA-262를 1997년에 공표한다.

ECMAScript는 자바스크립트뿐만 아니라 마이크로소프트의 JScript나 어도비의 액션스크립트도 따르는 국제 표준이 된다.

현재 자바스크립트의 최신 표준은 2015년에 발표된 ECMAScript 6이다. (ES6)
현재는 ES11까지 업데이트 되었다.





3. 자바스크립트의 동작 원리


1) 자바스크립트 엔진

자바스크립트를 해석하는 JavaScript Engine과 웹 브라우저에 화면을 그리는 Rendering Engine은 서로 다르다.

▶자바스크립트 엔진이란?

개발자가 작성한 자바스크립트 코드를 해석하고 실행시켜주는 것이 자바스크립트 엔진의 역할으로, 가능한 짧은 시간 내에 가장 최적화된 코드를 생성하는 것이 목표이다.
즉, 자바스크립트 엔진은 자바스크립트 코드를 실행하는 프로그램 혹은 인터프리터를 말한다.
표준적인 인터프리터로 구현될 수도 있고, 혹은 자바스크립트 코드를 바이트코드로 컴파일하는 JIT 컴파일러로 구현할 수도 있다. 여러 목적으로 사용될 수 있지만 주로 웹 브라우저를 위해 사용된다.

각각의 자바스크립트 엔진은 특정 버전의 ECMAScript를 구현하기 때문에, ECMAScript가 발전하는 만큼 엔진도 발전한다. 아래에 적혀있는 것과 같이 수많은 자바스크립트 엔진이 존재하는 이유도 각각의 엔진이 서로 다른 웹 브라우저, Node.js와 같은 런타임 등에서 동작하도록 만들어졌기 때문이다. 많은 자바스크립트 엔진 중 가장 알려진 것이 구글의 V8 엔진이다.


▶자바스크립트 엔진의 종류

V8 : 오픈소스로 구글에서 개발했습니다. C++로 작성되었으며, 구글 크롬과 Node.js에서 사용됩니다. 가장 유명합니다.

SpiderMonkey : 최초의 자바스크립트 엔진입니다. 넷스케이프 네비게이터 웹 브라우저를 위해 브랜던 아이크에 의해 개발되었습니다. 지금은 모질라 파이어폭스에 사용됩니다.

Rhino : 모질라 재단에서 운영합니다. 오픈소스이며, 전체가 자바로 개발되었습니다.

JavaScriptCore : 오픈소스, 니트로라는 이름으로도 알려져 있으며 애플이 사파리를 위해 개발했습니다.

Chakra(Jscript9) : 인터넷 익스플로러용입니다.

Chakra(JavaScript) : 마이크로소프트 엣지용입니다.

Nashron : 오픈JDK의 일환으로 오픈소스이며 Oracle Java Languages and Tool Group이 개발하였습니다.

JerryScript : 사물인터넷을 위한 경량 엔진입니다.


▶V8 작동 원리

V8은 구글에서 C++로 만든 고성능의 자바스크립트 엔진이다. 이를 통해 자바스크립트가 느리다는 인식이 바뀌었다.

1. 자바스크립트 소스코드를 가져와 Parser에게 넘긴다.
2. Parser는 파싱을 통해 AST(Abstract Syntax Tree)로 변환시킨다.
3. AST를 인터프리터를 통해 byte code로 변환(Ignition)한다.
4. 그리고 bytecode를 실행함으로써 실제 작동하게 된다.
5. 그 중 자주 사용되는 코드는 TruboFan으로 보내진다.
6. TruboFan은 이 코드를 Optimized Machine Code로 컴파일해놓고 사용한다.

  • V8은 8기통 엔진을 뜻한다.
  • Ignition은 엔진 시동시에 사용되는 점화기이다.
  • TurboFan은 너무 과호출되는 부분을 식혀주는 Fan이다.

▶자바스크립트 엔진의 구성(Heap, Call Stack)

<요약>
1. Memory Heap(엔진) : 변수와 객체의 메모리 할당이 발생하는 곳
2. Call Stack(엔진) : 코드 실행에 따라 호출 스택이 쌓이는 곳(함수가 실행되는 순서를 기억, 선입후출)
3. Callbak Queue(런타임) : 단일쓰레드 프로그래밍 언어인 자바스크립트(Call STack이 1개)에서 멀티 작업을 할 수 있도록 해주는 것
4. Event Loop(런타임) : Call Stack과 Callback Queue의 상태를 체크하여 Call Stack이 빈 상태가 되면, Callback Queue의 첫번째 콜백을 Call Stack으로 밀어 넣어줌 (틱) -> 자바스크립트에 동시성을 지원하게 해줌

1) 메모리 힙 (Memory Heap)

메모리 생존주기는 프로그래밍 언어와 관계없이 비슷하다.

  1. 필요할때 할당한다. (allocate)
  2. 사용한다. (읽기, 쓰기) (use)
  3. 필요없어지면 해제한다. (release)

두 번째 부분은 모든 언어에서 명시적으로 사용된다. 그러나 첫 번째 부분과 마지막 부분은 저수준 언어에서는 명시적이며, 자바스크립트와 같은 대부분의 고수준 언어에서는 암묵적으로 작동한다.

메모리 힙은 변수, 함수 저장, 호출 등의 작업이 발생하여 위 내용들이 진행되는 공간이다.
쉽게 생각하면 'Memory Heap'이라는 이름의 창고가 있고, 변수나 함수들은 겉에 이름이 라벨지로 붙어있는 박스들인거다.



2) 런타임(RunTime)

자바스크립트 런타임은 CallBack Queue와 EventLoop를 가지고 있다.

런타임이란 프로그래밍 언어가 구동되는 환경이라고 말한다.
예를들어 Node.js나 크롬 등의 여러 브라우저들은 자바스크립트가 구동되는 환경이기 때문에, Node.js나 브라우저들을 자바스크립트 런타임이라고 칭한다.

자바스크립트 엔진에서 제공해주는 것들은 아니지만 외부에서 자바스크립트에 관여하는 요소들이 있다. (ex. Web API(DOM,AJAX,setTimeout - 브라우저에서 제공) 등 이 있고 Web ApI의 호출을 제어하기 위한 Task Queue, Event Loop가 있다.(밑에 더 설명)

DOM events, http request, setTimeout과 같은 비동기 이벤트들을 다루기 위한 브라우저의 웹 API 스레드들은 브라우저 내부에 C++로 구현되어 만들어져있음



3) 호출 스택(Call Stack)

코드에 따른 자세한 스택 순서 설명 참고

Call Stack은 코드가 실행되면서 스택 프레임이 쌓이는 장소이다.

Call Stack은 기본적으로 우리가 프로그램 상에서 어디 있는지를 기록하는 자료구조 이다.
만약 함수를 실행하면, 해당함수는 call stack의 가장 상단에 위치한다.
그리고 함수가 끝나면 (return) 해당 함수를 호출 스택에서 제거한다.
이것이 스택의 역할이다.

function multiply(x, y) {
    return x * y;
}
function printSquare(x) {
    var s = multiply(x, x);
    console.log(s);
}
printSquare(5);

처음 엔진이 이 코드를 실행하는 시점에는 call stack이 비어있다. 하지만 코드가 실행되면서 call stack은 아래와 같이 변한다. (각 단계를 stack Frame이라고 함)

만약 스택의 사이즈를 초과했을때
1. 무한 반복문
2. 자기 자신을 호출하는 함수
등등..
이런 경우 call stack에 stack frame이 계속 쌓이게 되면서 스택오버플러우 에러가 발생한다.

자바스크립트는 싱글 쓰레드라 단 하나의 Call Stack을 가지고, 이는 하나의 함수가 실행되면 해당 함수의 실행이 끝날 때까지 다른 어떤 Task들도 수행될 수 없음을 의미한다.
만약 시간이 매우 오래 걸리는 작업이 스택에 쌓이고 실행되면 그 다음 작업은 무한정 대기(blocking) 를 할 수밖에 없다.

이러한 블로킹 상태를 극복하기 위한 해결방안이 바로 비동기 콜백이다.
(코드 일부를 실행하고, 나중에 실행될 콜백 함수를 제공하는 것이다.
!! call stack이 비었을 떄 콜백이 실행된다 !! )



4) Task Queue & Event Loop

자바스크립트의 런타임 환경에서는 처리해야하는 Task들을 임시로 저장하는 대기 Queue가 존재한다. (Task Queue)

Event Loop는 Call Stack이 비어있는지 아닌지, Task Queue에 Task가 존재하는지 아닌지를 판단하는 역할을 맡는다.

이 Task Queue에 들어있는 Task들은 Call Stack이 비어있을 때, 대기열에 들어온 순서대로 실행된다.

자바스크립트에서 비동기로 호출되는 함수들은 Call Stack에 쌓이는 것이 아닌 Task queue에 쌓이게 된다. 자바스크립트 엔진 영역이 아닌 WebAPI(AJAX, SetTimeout 등등..)은 비동기로 실행된다.

코드로 보면

function quiz1(){
  console.log("quiz1");
  quiz2();
}
function quiz2(){
  let timer = setTimeout(function(){
      console.log("quiz2");
    },0);
  quiz3();
}
function quiz3(){
  console.log("quiz3");
}
quiz1();

이 코드를 실행시켜보면,

  1. 콘솔에 quiz1 출력된다.

  2. quiz2()가 호출되면서 setTimeout()가 call stack에 들어갔다가 빠져나온다(pop).

  3. 이때 setTimeout() 내부에 quiz2를 출력할 익명함수는 Task Queue 영역으로 들어간다.

  4. 그 다음 quiz3()이 콜스택에 들어간다.(push)

  5. quiz3 출력

  6. quiz3()이 끝나면서 콜스택에서 사라지고(pop) 뒤이어 quiz2 -> quzi3도 차례로 사라진다.

  7. 이때 콜스택이 비워지고, Task Queue에 있던 첫번째 task를 가져와 Call Stack에 넣게 되고, 익명함수가 실행되면서 quiz2가 출력된다.

결과적으로 이 순서로 출력된다.

quiz1
quiz3
quiz2

이벤트 루프는 Call Stack과 Callback Queue의 상태를 체크하여
Call Stack이 빈 상태가 되면, Callback Queue의 첫번째 콜백을 Call Stack으로 밀어 넣는걸 말한다.

이러한 반복적인 행동을 틱(Tick)이라고 부른다.

이렇게 이벤트 루프라는 것을 통해 자바스크립트에게 동시성을 지원하게 해준다.

그런데 콜백 함수를 중첩해서 사용하게 되면 반복된 들여쓰기로 인한 가독성저하와 유지보수의 어려움으로 인해 콜백지옥이라는 상황을 겪게 되고 이를 해결하는 방법으로
promise , async/await 같은 방법들로 대체되고 있다.




4. 자바스크립트 삽입 위치

브라우저는 렌더링 도중 자바스크립트를 만나게 되면 이에 대한 해석과 실행이 완료될 때까지 렌더링을 멈춘다. 그렇기 때문에, 렌더링이 정상적으로 끝난 후 실행하기 위해 바디 하단에 스크립트를 두는게 안정적이라는 말을 한다.

  1. head에 삽입되는 경우
  • 무거운 스크립트가 실행되는 경우 렌더링에 방해가 될 수 있다.
  • 제이쿼리와 같은 설정을 위한 스크립트들이 사용된다.
  • DOM이 필요할 경우 document.onload 를 사용하여, load 이벤트 발생 시, 실행되도록 할 수 있다.
  1. 바디 하단에 삽입되는 경우
  • 브라우저의 렌더링이 완료 된 후 실행되기 때문에, DOM을 조작할 수 있다.
  • 하지만! 헤드 태그에서 발생할 수 있는 문제를 해결하기 위해 추가된 속성이 있다.
    바로, async와 defer이다.

위와 같이 async 또는 defer 속성이 추가된 스크립트는 렌더링을 방해하지 않는다.
async 속성은 외부 스크립트에만 사용할 수 있으며, 스크립트를 내려받는 즉시 실행된다.

defer 속성은 비동기적으로 스크립트를 다운로드 하며, 렌더링이 완료된 후 스크립트를 실행한다.




지금 한건 뭔가 AJAX 작동 원리 느낌.
다른 자바스크립트 엔진들이랑 비교해보고 시장순위 볼 것
<참고링크>
자바스크립트 기초 -1 자바스크립트 엔진
자바스크립트 동작 원리
자바스크립트 동작원리를 살펴봅시다
자바스크립트의 동작원리 : 엔진,런타임,호출 스택

profile
연애하는 개발자

0개의 댓글