출처: https://bumcrush.tistory.com/182 [맑음때때로 여름]

상세 컨텐츠

본문 제목

Week2(Javascript)

MOFE 스터디

by 장동균 2020. 9. 24. 12:10

본문

1.

 

자바스크립트는 동적 언어이면서 인터프리트 언어이다. 이 때문에 변수의 타입이 런타임에 결정된다. 간단한 프로그램을 만든다면 상관 없겠지만, 복잡한 프로그램에서 변수의 타입이 런타임에 결정되는 것은 프로그래머의 실수를 유발하기 쉽다. 이러한 자바스크립트의 단점을 보완하기 위해 타입스크립트가 나왔다.

 

  + 인터프리트 언어란 코드를 한줄 한줄 읽어가며 명령을 처리하는 방식. Interpreter(통역사)를 생각하면 확실히 더 오래 기억에 남을 것 같다. 이렇게 한줄 한줄 읽어가며 명령을 처리하다 보니 그 속도가 컴파일러 언어에 비해 느린 것이다. 대신 한 줄씩 읽어들이기에 명령이 잘못 입력됐을 때 바로 수정할 수 있다는 장점도 지닌다,

 

ryusm.tistory.com/105

 

스크립트 언어와 컴파일 언어의 차이

컴파일 언어와 스크립트 언어의 차이 우리가 작성한 코드를 컴퓨터가 알아듣기 위해서는 프로그래밍 언어를 기계어(0, 1)로 번역하는 과정이 필요한데, 그 과정을 언어에 따라 컴파일(compile) 혹��

ryusm.tistory.com

sangwoo0727.github.io/javascript/JavaScript-1_1_DynamicStaticLang/

 

[JavaScript] 동적언어와 정적언어

들어가기 전 자바스크립트에 대해 공부를 하며 포스팅을 하기로 마음먹었다. 먼저 자바스크립트는 대표적인 동적언어인데, 이에 대한 포스팅을 하며 자바스크립트의 문을 열어보려 한다.정적 �

sangwoo0727.github.io

www.youtube.com/watch?v=ViS8DLd6o-E&t=2803s

 


2. 

 

브라우저는 크게 렌더링 엔진과 자바스크립트 엔진으로 나뉜다.

렌더링 엔진


서버로부터 받은 HTML, CSS은 브라우저 렌더링 엔진의 HTML 파서, CSS 파서에 의해 DOM, CSSOM 트리가 만들어지고 렌더 트리로 결합된다. 렌더 트리를 기반으로 브라우저는 웹페이지를 표시한다.


자바스크립트 엔진


자바스크립트 처리는 자바스크립트 엔진이 하며 JS로 작성한 코드를 해석하고 실행하는 인터프리터다. 렌더링 엔진의 HTML 파서가 DOM 생성 프로세스를 하던 중 스크립트 태그를 만나면, 자바스크립트 코드를 실행시키기 위해 자바스크립트 엔진에게 제어권한을 넘겨 주게 된다. DOM 트리가 다 형성되지 않았는데 자바스크립트에서 해당 DOM을 조작하려고 하면 문제가 발생하기 때문에 <script> 태그는 html의 body 태그 제일 아래에 놓는 것이 좋다.


이 자바스크립트 엔진 중 가장 유명한 것은 구글의 V8엔진이다. 이 V8엔진의 특징으로는

 

1. V8엔진은 크롬과 노드js에서 사용한다.
2. V8엔진은 크게 세 부분으로 나뉜다. 메모리힙과 콜스택, 콜백큐
3. V8엔진은 인터프리터를 사용하는 대신 자바스크립트 코드를 더 효율적인 머신 코드로 번역한다. JIT compiler(which compiles JavaScript to executable bytecode just as it is about to run)를 통해

 


V8엔진의 세 부분인 메모리힙, 콜스택, 콜백큐가 어떤 식으로 작동하는지에 대해 굉장히 잘 설명되어 있다고 생각한다.

 

velog.io/@imacoolgirlyo/JS-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%97%94%EC%A7%84-Event-Loop-Event-Queue-Call-Stack

 

[JS] 자바스크립트 엔진, Event Loop, Event Queue, Call Stack

브라우저의 동작원리와 자바스크립트 함수, Event, Ajax ,Timer 같은 Web API들이 어떤 순서로 처리되는지 알아보자. 브라우저 동작 원리 브라우저는 크게 렌더링 엔진, 자바스크립트 엔진으로 나뉜다.

velog.io

V8엔진 세 부분에 대한 내용이 그림으로 되어있어서 위의 글과 같이 읽어보면 이해를 하는데 큰 도움이 된다.

 

engineering.huiseoul.com/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94%EA%B0%80-%EC%97%94%EC%A7%84-%EB%9F%B0%ED%83%80%EC%9E%84-%EC%BD%9C%EC%8A%A4%ED%83%9D-%EA%B0%9C%EA%B4%80-ea47917c8442

 

자바스크립트는 어떻게 작동하는가: 엔진, 런타임, 콜스택 개관

How JavaScript works: an overview of the engine, the runtime, and the call stack

engineering.huiseoul.com

V8엔진에서 JIT compiler를 통해 컴파일하는 과정이 잘 설명되어 있다.                                  medium.com/@pks2974/v8-%EC%97%90%EC%84%9C-javascript-%EC%BD%94%EB%93%9C%EB%A5%BC-%EC%8B%A4%ED%96%89%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-%EC%A0%95%EB%A6%AC%ED%95%B4%EB%B3%B4%EA%B8%B0-25837f61f551

 

 

V8 에서 Javascript 코드를 실행하는 방법 정리해보기

V8 에서 Javascript 가 어떻게 해석되어, 실행 되는지 이해하기 위해 정리 해보고자 한다.

medium.com

 


 

자바스크립트는 단일 쓰레드 이면서 콜백 큐를 사용한다
단일쓰레드를 사용하기 때문에 데드락과 같은 멀티쓰레드 기반 환경에서 벌어질 수 있는 문제들을 신경쓰지 않아도 된다. 하지만, 단일 쓰레드이기에 가지는 단점이 있는데 바로 엄청나게 시간이 오래 걸리는 함수가 들어왔을 때 이다. 자바스크립트의 콜스택은 1개이고 이곳에 엄청나게 시간이 오래 걸리는 함수가 들어가게 되면 블록킹되어 다른 일들을 처리할 수 없게 된다.

 

이를 해결하기 위한 내용이 아래의 링크에 잘 정리되어 있는데 지금의 나로서는 솔직히 이해하지 못하겠다. 운영체제를 공부하는 중이니 이번 학기가 끝나고 운영체제를 조금 아는 상태에서 다시 이 글을 본다면 그때는 이해할 수 있지 않을까라는 기대를 가져본다.

 


engineering.huiseoul.com/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94%EA%B0%80-v8-%EC%97%94%EC%A7%84%EC%9D%98-%EB%82%B4%EB%B6%80-%EC%B5%9C%EC%A0%81%ED%99%94%EB%90%9C-%EC%BD%94%EB%93%9C%EB%A5%BC-%EC%9E%91%EC%84%B1%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8B%A4%EC%84%AF-%EA%B0%80%EC%A7%80-%ED%8C%81-6c6f9832c1d9

 

자바스크립트는 어떻게 작동하는가: V8 엔진의 내부 + 최적화된 코드를 작성을 위한 다섯 가지 팁

How JavaScript works: inside the V8 engine + 5 tips on how to write optimized code

engineering.huiseoul.com


3.

 

JavaScript is an interpreted language so we cannot call them compiler errors but instead parsing errors.

 

즉, 자바스크립트는 인터프리트 언어이기에 문법적인 오류들은 compile error가 아닌 parsing error라고 부른다.

 

보통 컴파일 에러(파싱 에러)가 생기는 경우는

 

  • ; 을 빼먹는 경우 (물론, 자바스크립트에서는 세미 콜론을 쓰지 않아도 된다.)
  • 맞춤법이 틀린 경우
  • 선언되지 않은 변수 사용

보통 런타임 에러가 생기는 경우는

 

  • 0으로 나누는 경우
  • null point error
  • 무한 루프
  • segmentation fault

4. try catch 구문

 

 

try catch 구문은 동기적으로 동작한다. 따라서 try catch 구문 내부에 비동기코드를 작성해서는 안된다.

 


5. promise와 async/await

 

(제로초님의 유튜브 강의를 참고했습니다.)

 

 const promise = new Promise((resolve, reject) => {
	if(condition) {
	 resolve('성공');
     } else {
	 reject('실패');
     }
 });

이 부분은 동기적으로 실행된다. 성공하면 resolve가 실행될 것이고, 실패하면 reject가 실행된다. 이 결과값은 promise 변수에 저장된 상태로 기다린다.

 

 promise
    .then((message) =>{
	console.log(message);
    })
    .catch((error)=>{
    console.error(error);
    })

promise 변수에 저장된 결과를 나중에 then 혹은 catch를 통해 받을 수 있는 것이다. 위에서 resolve가 실행되었다면 then이 실행될 것이고 reject가 실행되었다면 catch가 실행될 것이다.

 

콜백과 프로미스의 가장 큰 차이점은 실행 시점에 대한 코드의 위치이다. 콜백을 사용하면 실행 시점에 대한 코드(내 글에서의 두번째 코드)가 선언부(내 글에서의 첫번째 코드)와 붙어있어야 한다.(사실상 섞여야 한다는 표현이 맞을 것도 같다)


하지만, 프로미스의 경우는 선언부와 실행 시점의 코드를 분리 할 수 있다. 즉, 이 말은 첫번째 코드와 두번째 코드 사이에 다른 여러 코드들이 들어와도 무방하다는 뜻이다.

 

가독성 측면에서 이것은 중요한 차이이다. 이런 기능이 없는 콜백에서는 코드 실행 순서가 보여지는 코드의 흐름과 다르기 때문에 이해하기 어렵다.  

 

또한, 다른 차이점들도 여럿 존재하는데 다음과 같다.

async 함수도 프로미스 객체를 반환한다는 점에서 프로미스와 유사하다.

 

async 함수의 사용방법을 예제를 통해 설명하자면

 async function foo() {
    return 'foo';
 }

이 foo함수의 리턴값인 문자열 foo를 받기 위해서는 foo().then((result)=>...); 혹은 const result=await foo(); 와 같이 코드를 작성할 수 있다. async 함수가 반환하는 값이 프로미스 객체이기에 then 혹은 await으로 받는 것이다.

 

즉, then과 await은 비슷한 개념이라고 생각하면 이해하기 쉬울 것 같다. 하지만, 코드를 이해하는데 있어서 아주 조금 다른 점은 then은 위에서 아래로 await은 오른쪽에서 왼쪽으로 이동한다고 생각해야 한다는 것이다.(이렇게 생각해야 이해가 쉽기 때문.)

 

promise.then((result) => ...) // then(promise 객체의 resolve)을 실행해서 그 결과값을 result로 받고 그 이후에 이                                              result 내용을 활용한다.

 

const result = await promise //(오른쪽에서 왼쪽으로 가기 때문에, promise의 then(then과 await을 같은 개념이라 생각)을 실행해서 그 값을 result에 넣는다. 이 result의 값은 이후에 나오는 행에서 활용된다.

 

await이 then과 비슷한 개념이기 때문에 await도 promise의 resolve 부분만을 실행한다. await으로는 promise의 reject 부분을 처리할 수 없기 때문에 try catch 구문을 사용해서 표현한다.

 

비동기를 확실히 이해하지 못해 여기서 조금 헷갈렸던게!! 

 

try/catch 구문 내부는 동기적으로 동작하는데 이 안에 비동기 코드를 어떻게 사용할 수 있는지 햇갈렸다.

 

이를 설명하기 위해서 가장 먼저 왜 비동기를 사용하는지에 대한 확실한 이해가 필요하다. 

자바스크립트에서 비동기 처리가 필요한 이유는 자바스크립트가 싱글 쓰레기이기 때문이다. A, B, C 3개의 프로그램이 있고 B와 C는 1초가 걸리는 반면 A는 10초가 걸리는 작업이라 생각해보자. 동기적으로 실행하게되면 A 프로그램이 가장 먼저 실행될 것이도 A 프로그램이 처리되는데 필요한 10초동안 자바스크립트는 싱글 스레드라는 특징 때문에 다른 일을 처리하지 못한다. 이런 경우 비동기처리를 통해 B와 C 프로그램을 먼저 처리하는 것이 훨씬 더 효율적이다.(위에 더 자세하게 설명 되어 있다.)

 

//모던 자바스크립트 페이지에 있는 코드이다.

async function f() {

  try {
    let response = await fetch('http://유효하지-않은-url');
    let user = await response.json();
  } catch(err) {
    // fetch와 response.json에서 발행한 에러 모두를 여기서 잡습니다.
    alert(err);
  }
}

f();

대충 이런 코드가 있다 생각한다. 처음 이런 코드를 보고 나서 내 생각은 "await은 비동기! fetch 작업과 resonse를 json객체화 하는 작업이 한꺼번에 비동기로 처리되겠구나. 오 근데 try/catch 구문 안에서는 동기적으로 실행이 이루어져야 하는데 이게 가능한가?" 라고 생각했다.

 

근데 이것은 내가 await은 then과 비슷한 것이고 await은 오른쪽에서 왼쪽으로 간다는 개념을 까먹었기 때문에 했던 실수였다. 

 

위의 코드를 대충 프로미스 체인 형태로 바꾸면

fetch("http://유효하지-않은-주소")
  .then((result) => {
    result.json();
  })
  .then((user) => {
    //user data 활용
  })
  .catch((error)=>{
    console.error(error);
  });

 이런 모양이 될 것이다. then의 내부는 비동기로 처리 되지만 then과 그 다음 then은 순서대로 즉 동기적으로 처리된다.  첫번째 then의 처리가 완료되면 그때 새로운 프로미스 객체를 반환하고 그 객체에서 resolve를 새로운 then이 받는 것이다. 

 

 저 위에서 적은 async/await 구문도 마찬가지이다. await 이하에 나오는 fetch와 reponse.json()은 비동기로 처리된다. 하지만, 이 await과 await 사이는 동기적으로 처리된다.(즉, fetch가 완료되고 그 값이 response 변수에 저장이 된 이후에 그 다음 비동기코드인 response.json()이 실행된다.)

 

 즉, 여러 개의 await와 여러 개의 then은 비동기로 처리하는 여러 개의 작업들이 순차적(동기적)으로 처리되어야 할 때 사용하는 것이다. 이 때문에 내부가 동기적으로 처리되어야 하는 try/catch 구문 내에서 여러 개의 await을 사용할 수 있는 것이다.

 

 then은 직관적으로 '그 다음' 이라는 의미를 가지기 때문에 이러한 과정을 이해하기 편했는데 await은 '기다리다' 라는 의미이기 때문에 직관적으로 이해하기 어려웠던 것 같다. await은 then이다. 그리고 오른쪽에서 왼쪽으로 간다라는 생각을 하고 있었다면 헷갈리지 않았을 수도 있었을 것 같다. 

 

이런 이해하기 어려운 비동기 테크닉을 사용하는 경우는 크게 4가지가 있다.

  1. 사용자 입력이 있을 때
  2. Ajax 호출을 비롯한 네트워크 요청
  3. 파일을 읽고 쓰는 등의 파일시스템 작업
  4. 의도적으로 시간 지연을 사용하는 기능

또, 예전에는 await을 사용하기 위해서는 반드시 async의 내부에 있어야 했는데 지금은 그렇지 안다고 한다.

 

 

 

프로미스체인에 있는 then마다 catch를 붙이는건가........???????????????????


6. ES6 vs commonJS

 

commonJs 

 

commonJS는 Node.js의 표준.

내보내기의 경우 exports, module.exports를 사용.

가져오기의 경우 require를 사용

 

ES6

 

아직 브라우저들이 ES6를 완벽히 지원하지 못하는 상황이므로 babel이 필요.

내보내기의 경우 export, default 사용.

가져오기의 경우 import 사용.

 

bigstar-vlog.tistory.com/29?category=1135300

 

JavaScript CommonJS, ES6 모듈 시스템

* 아래의 글은 JavaScript 프롤로그 및 목차를 먼저 읽으신 후 읽으시기를 권장합니다. 본 글에서 다룰 내용 모듈 CommonJS ES6 모듈? 모듈이란 여러 기능들에 관한 코드가 모여있는 하나의 파일로 아래

bigstar-vlog.tistory.com

더 자세한건 여기.

 


 

'MOFE 스터디' 카테고리의 다른 글

Week6(JavaScript)  (0) 2020.10.28
Week5(Javascript)  (0) 2020.10.17
Week4(Javascript)  (0) 2020.10.11
Week3(Javascript)  (0) 2020.10.02
Week1(Javascript)  (0) 2020.09.15

관련글 더보기

댓글 영역