Javascript 내부에 대해 자세히 알아보기

Feb 02 2023
Javascript 엔진, 이벤트 루프, 웹 API, 이벤트 대기열 및 콜백의 내부 작업. 소개 Javascript가 없었다면 어떤 일이 벌어졌을지 상상해 본 적이 있습니까? Javascript가 없으면 Netflix에서 영화를 스트리밍하거나 Amazon에서 쇼핑하거나 Youtube에서 비디오를 볼 수 없습니다.

Javascript 엔진, 이벤트 루프, 웹 API, 이벤트 대기열 및 콜백의 내부 작업.

자바스크립트

소개

Javascript가 없었다면 어떤 일이 벌어졌을지 상상해 본 적이 있습니까? Javascript가 없으면 Netflix에서 영화를 스트리밍하거나 Amazon에서 쇼핑하거나 Youtube에서 비디오를 볼 수 없습니다. 거의 모든 다른 웹 사이트는 Javascript를 사용하고 웹 페이지를 대화식으로 만듭니다.

Javascript가 발명되기 전에 인터넷은 일반 HTML 페이지로 구성되었습니다. HTML 과 CSS는 웹 페이지에 구조와 스타일을 부여합니다. 그러나 Javascript는 웹 페이지를 동적으로 만듭니다 . 자격 증명을 입력하고 웹 사이트에 로그인하거나 온라인 거래를 수행하거나 게임을 할 수 있습니다. 자바스크립트는 모든 것을 가능하게 합니다.

Stack-overflow에서 수행된 설문 조사 중 하나는 Javascript가 GitHub에서 가장 많은 수의 리포지토리를 가지고 있는 것으로 나타났습니다. 매년 새로운 프레임워크와 라이브러리가 Javascript로 개발되고 있습니다. 이 언어는 진정으로 인터넷을 변화시켰고 사람들의 삶을 단순화했습니다.

배경

2년 전, 저는 사이드 프로젝트를 진행 중이었고 처음으로 Javascript를 사용했습니다. 지난 10년 동안 노련한 프로그래머가 되어 구문에 정통하게 되었고 3개월 만에 좋은 명령을 개발했습니다.

몇 달이 지나자 내가 개발한 웹 페이지가 제대로 작동하지 않았습니다. 로드하는 데 오랜 시간이 걸리고 고객에게 영향을 미치기 시작했습니다. 그래서 근본 원인을 파악하기 위해 심층 분석을 수행했습니다.

잠 못 이루는 밤을 보낸 끝에 결국 정신을 잃고 포기하려던 참이었다. 그러나 나는 마지막 시도를하기로 결정했습니다. 마지막으로 Javascript가 내부적으로 어떻게 작동하는지 철저히 이해해야겠다고 생각했습니다. 나는 많은 리소스를 참조했고 마침내 이틀 안에 내 코드의 버그를 수정할 수 있었습니다.

엔지니어는 일반적으로 새로운 것을 구축하는 데 중점을 둡니다. 우리가 사용하는 도구와 프레임워크는 대부분의 복잡성을 숨깁니다. 우리의 여정에서 우리는 뒤에서 일이 실제로 어떻게 작동하는지 잊는 경향이 있습니다. 우리가 사용하는 모든 도구의 내부 작동 방식을 알아야 합니다. 내부를 잘 이해하면 문제의 범위를 좁히고 실용적인 해결책을 찾는 데 도움이 됩니다.

이 기사에서는 브라우저에서 Javascript가 실행될 때 뒤에서 어떤 일이 발생하는지 살펴보겠습니다. Javascript 엔진을 살펴보고 작동 방식을 이해할 것입니다. Javascript 런타임과 관련된 다양한 구성 요소를 확인하고 이벤트 루프 및 이벤트 큐에 대해 명확하게 알 수 있습니다. 이러한 용어가 생소할 수 있지만 이 기사에서는 각 용어를 단순화하려고 노력할 것입니다. Javascript의 내부를 마스터하기 위한 탐구부터 시작하겠습니다.

자바스크립트

Javascript는 고급 해석 언어입니다. C나 C++와 달리 Javascript 코드를 컴파일한 다음 실행할 필요가 없습니다. Javascript 코드는 먼저 바이트코드로 컴파일된 다음 기계 수준 코드로 변환됩니다.

Java, C, C++, C#과 같은 고급 언어는 멀티스레딩을 지원합니다. 이러한 언어를 통해 프로그래머는 여러 스레드를 만들고 다른 스레드에서 작업을 실행할 수 있습니다. 따라서 여러 CPU에서 작업을 생성하고 컴퓨팅 리소스를 효율적으로 활용할 수 있습니다.

반면 Javascript는 단일 스레드입니다. 이는 주어진 순간에 실행 스레드가 하나만 있음을 의미합니다. 시간이 걸리는 javascript 기능을 실행하면 웹 페이지가 정지됩니다. 탐색하는 동안 웹 사이트가 응답하지 않는 오류를 여러 번 보았을 것입니다 .

페이지 응답 없음 오류

빠른 데모를 수행하고 작업을 살펴보겠습니다. Twitter를 열었고 Trending, News등과 같은 개별 탭을 클릭할 수 있습니다 Sports.

Twitter의 탐색 섹션

이제 내 콘솔에서 무한developer 루프 가 포함된 함수를 작성하고 있습니다 . 아래는 함수의 정의입니다.

function infiniteLoop() {
    for(i=0; i < 100000; ) {
    }
}
infiniteLoop()

Sports아래 GIF는 탭을 또는 로 변경할 수 없음을 보여줍니다 Entertaintment.

무한 루프로 인해 화면이 멈춤

함수에 무한 루프가 포함되어 있으므로 계속해서 무한 실행됩니다. 다른 탭을 선택하면 브라우저가 이벤트를 처리 click하고 그에 따라 클릭한 탭의 내용을 표시합니다. Javascript가 이미 기능을 실행 중이므로 다른 탭을 선택할 수 없습니다 infiniteLoop.

위의 예에서 볼 수 있듯이 Javascript에서는 한 번에 하나의 기능만 실행할 수 있습니다. 이제 브라우저가 몇 초 만에 복잡한 웹사이트를 로드할 수 있는 방법에 대해 질문할 수 있습니다.

다음 섹션에서 Javascript가 이 마법을 배후에서 수행하는 방법을 이해할 것입니다. 이제 Javascript의 핵심인 Javascript Engine에 대해 알아봅시다.

자바스크립트 엔진

모든 브라우저는 자체 Javascript 엔진을 제공합니다. 예:- Chrome은 V8 엔진을 사용하고 Firefox는 SpiderMonkey 엔진을 사용합니다. 엔진은 Javascript 코드를 한 줄씩 실행하는 역할을 합니다. 다음은 널리 사용되는 브라우저 및 Javascript 엔진 목록입니다.

Javascript 엔진은 Heap 과 Stack 으로 구성됩니다 . 이 두 요소의 작용을 이해합시다.

더미

힙 은 함수 정의, 개체 변수를 저장하는 역할을 합니다. 여기에는 코드에서 참조하는 모든 개체가 포함됩니다.

객체는 힙에 동적으로 생성됩니다. 작업은 자바와 유사합니다. 객체가 함수에 의해 참조될 때마다 힙에서 가져옵니다.

function bar() {
    var player = { "firstName": "Shubhman",
                   "lastName": "Gill"
                 }
    var teams = ["India", "NewZealand"]
    i =0
    a = 10
    console.log("In the function bar")
}

bar()

      
                
Objects on Heap

스택

스택 은 후입선출(LIFO) 데이터 구조입니다. 함수가 실행될 때마다 함수의 지역 변수가 스택에 푸시됩니다. 함수 실행이 완료되면 스택에서 제거됩니다. 함수가 실행 중에 새 함수를 호출하면 새 함수도 스택에 푸시됩니다. 엔진은 스택의 맨 위에 있는 함수를 실행합니다.

스택 맨 아래에 있는 함수는 그 위에 있는 모든 함수가 반환되면 실행을 다시 시작합니다. 함수가 오류를 발생시키는 경우 스택 추적이 에 인쇄됩니다 console. 스택 추적은 예외가 발생했을 때 호출된 함수 체인으로 구성됩니다. 한 가지 예를 살펴보겠습니다.

브라우저에서 위의 코드를 실행하겠습니다. 그리고 함수에 중단점을 추가합니다 city.

브라우저에서 자바스크립트 실행

위에서 볼 수 있듯이 스크립트를 실행하면 함수의 중단점에서 중지됩니다 city. 오른쪽 섹션에서 상단에 기능을 Call Stack볼 수 있습니다 .city

Call Stack지금까지 호출된 모든 함수로 구성됩니다 . 그리고 가장 최근의 함수가 맨 위에 위치합니다. 함수 실행이 완료되면 스택에서 제거됩니다.

아래 이미지에서 함수가 city제거되고 라인 번호 9의 함수에 대한 실행이 계속되는 것을 볼 수 있습니다 street.

위에서 본 것처럼 Javascript는 한 번에 하나의 기능만 실행할 수 있으며 실행 스레드는 하나뿐입니다. 실행 스택에서 여러 함수를 동시에 실행할 수 없습니다.

호출을 수행하고 다른 웹사이트에서 데이터를 가져오는 함수가 있다고 가정해 보겠습니다 HTTP. 서버가 느리고 함수를 실행하는 데 오랜 시간이 걸리면 어떻게 될까요? 우리는 다른 기능을 실행할 수 없으며 사용자 경험이 매우 좋지 않을 것입니다.

현실 세계에서 이런 일이 발생합니까? 아니요, Facebook.com , Twitter.com , Amazon.com 등과 같은 복잡한 웹사이트는 사용자 경험에 영향을 주지 않고 수많은 Javascript 코드를 실행합니다. 방법을 이해하기 위해 Javascript 런타임에 대해 자세히 살펴보겠습니다.

자바스크립트 런타임

Javascript는 서버에서 데이터를 가져오거나, DOM을 조작하거나, 타이머를 사용하여 기능을 실행할 수 있는 다양한 API를 제공합니다. Javascript의 단일 스레드 특성으로 인해 웹사이트 렌더링이 중단되어 성능이 저하될 수 있습니다. 그러나 Javascript 런타임은 이러한 일이 발생하지 않도록 합니다. 예를 들어 이것을 이해합시다.

아래 코드의 출력이 무엇인지 짐작할 수 있습니다.

getSubTitles인쇄 후 인쇄 됩니까 getActors? 그리고 호출 후 setTimeout코드가 중단됩니까?

다음은 위의 코드를 실행하여 생성된 출력입니다.

코드 출력

위와 같이 가 getSubTitles먼저 인쇄되고 4초 후에 getActors인쇄되었습니다. 그러나 함수는 setTimeout4초 동안 기다렸지만 여전히 getSubTitles이전에 후속 함수를 실행했고 코드는 기다리지 않았습니다. 이제 무대 뒤에서 무슨 일이 있었는지 이해합시다.

웹 API

setTimeout또는 fetchJavascript 소스 코드 어디에서도 같은 기능 구현을 찾을 수 없습니다 . 이러한 기능은 브라우저에서 제공되며 Javascript의 일부가 아닙니다. 구현은 브라우저마다 다릅니다.

브라우저는 네트워크 호출을 수행하고, DOM을 조작하고, 오디오, 비디오를 처리하는 등의 기능을 제공합니다. 이러한 기능은 웹 API를 구성합니다. 내부 구현은 복잡하며 주로 C++ 코드로 구성됩니다. API는 Javascript 코드에서 호출할 수 있는 인터페이스를 제공합니다.

와 같은 함수를 호출하면 setTimeoutJavascript는 이것이 Web API임을 이해합니다. 그런 다음 이 함수의 실행을 Web API 컨테이너에 위임합니다. 함수는 setTimeout별도의 스레드에서 실행됩니다. Javascript의 실행 스레드에서는 실행되지 않습니다. setTimeout이후에 작성된 코드가 콜백 함수가 전달되기 전에 실행되는 이유입니다 .

마찬가지로 네트워크 호출에는 시간이 걸리므로 와 같은 기능은 fetch별도의 스레드에서 실행됩니다. 브라우저 웹 API는 대부분의 복잡성을 숨깁니다. 예를 들어:- 내부 구현에는 fetchTCP 연결 형성, 데이터 전송 및 구문 분석이 포함됩니다. 또한 적절한 스레드에서 실행을 예약하여 컴퓨팅 리소스를 효율적으로 사용합니다.

아래 gif는 setTimeout.

자바스크립트 실행

위에서 본 것처럼 함수가 호출되면 콜백 함수를 웹 API로 setTimeout보냅니다 . getActors웹 API 컨테이너에서 함수는 setTimeout4초 동안 기다립니다. 그 동안 후속 함수가 getSubTitles호출됩니다.

이제 getActors타이머가 종료된 후 콜백 함수가 어떻게 실행되는지 물어볼 수 있습니다. 다음 섹션에서 웹 API가 반환된 후 콜백이 실행되는 방법을 살펴보겠습니다.

이벤트 대기열

Javascript는 콜백 함수에 크게 의존합니다. 콜백 함수는 이벤트가 발생하면 실행됩니다. 예:- 서버로부터 응답을 받은 후 json표현을 인쇄해야 합니다. 또는 4초 지연 후 기능을 실행합니다.

Javascript 런타임은 이벤트 대기열 또는 콜백 대기열로 알려진 구성 요소로 구성됩니다. 메시지 대기열이며 FIFO(First In First Out) 순서를 사용합니다. 메시지는 실행 예정인 콜백 함수에 불과합니다.

이를 이해하기 위해 예를 들어보자. 아래 코드에서는 버튼 클릭 이벤트가 있을 때마다 콜백 함수를 등록합니다. 사용자가 버튼을 클릭하면 함수가 onClick호출됩니다. timer이 함수는 2초의 지연 후에 함수를 호출합니다 .

위의 애니메이션은 뒤에서 일어나는 일을 보여줍니다. $.on여기에는 a) 및 b) 라는 두 가지 Web API가 있습니다 setTimeout. 첫 번째 API는 클릭 이벤트가 발생하기를 기다립니다. 클릭 이벤트를 받으면 함수를 실행합니다 onClick. 두 번째 API는 setTimeOut이후에 함수에 의해 호출됩니다 onClick.

사용자가 버튼을 클릭할 때마다 함수가 onClick이벤트 대기열에 푸시됩니다. 마찬가지로 타이머가 종료되면 함수가 timer대기열에 푸시됩니다. 따라서 이벤트 큐는 실행해야 하는 모든 콜백 함수로 구성됩니다. 이 경우 onClick기능 timer.

이벤트 루프

콜백 함수는 EventQueue이벤트 루프를 통해 Javascript의 실행 스택에 도달합니다. 이벤트 루프는 현재 Javascript 스택이 비어 있는지 지속적으로 확인합니다. 스택이 비어 있는 경우 이벤트 큐에서 첫 번째 메시지를 선택하고 스택에 푸시합니다.

이전 섹션의 예를 들면 이벤트 루프가 스택이 비어 있음을 확인하는 즉시 콜백 큐에서 다음 메시지를 가져와 실행합니다.

아래는 이벤트 루프 작업을 위한 대략적인 의사 코드입니다.

이벤트 루프는 실행 스택을 지속적으로 모니터링하는 무한 루프로 생각할 수 있습니다. 스택이 비어 있는 경우 이벤트 큐에서 메시지(함수)를 선택하여 실행합니다.

아래 다이어그램은 Javascript 런타임의 상위 수준 표현을 보여줍니다.

자바스크립트 런타임

지금까지 Javascript 런타임의 다양한 구성 요소를 살펴보았습니다. 이제 Javascript가 내부에서 어떻게 작동하는지 더 잘 알게 될 것입니다. 지금까지 배운 내용을 정리해 보겠습니다.

요약

  • Javascript는 단일 스레드이며 한 번에 하나의 기능을 수행합니다.
  • 웹 API를 활용하여 백그라운드에서 복잡한 작업을 실행합니다.
  • 웹 API 실행이 완료되면 콜백 함수를 이벤트 대기열로 보냅니다.
  • 이벤트 루프는 Javascript 스택이 비어 있는지 지속적으로 확인합니다. 스택이 비어 있는 경우 이벤트 큐에서 콜백 함수를 선택하여 실행합니다.