프론트엔드 스터디 - 1

Hyeon·2021년 11월 30일
0

script 태그의 위치 에 따른 문제점과 해결방안

브라우저가 html 문서 파싱을 하다가 script 태그를 만나게 되면 파싱을 멈추고 script를 로딩, 실행 한 후에 이어서 파싱을 하게 됩니다. 이것 때문에 위치에 따른 차이점이 발생하게 됩니다. script 태그는 문서 내에 어디든 위치할 수 있지만 head 태그의 내부, 그리고 body 최하단에 두었을 때로 나누어서 설명해 보겠습니다. 먼저 head 내부에 script를 위치시키면 body 태그 내부를 파싱 해서 DOM 트리를 생성하기 전에 먼저 script를 로드하고 실행하게 됩니다. 이렇게 되면 문제 2가지가 있을 수 있는데, 먼저 script 파일이 크거나 개수가 많으면 로드하고 실행하는데 시간이 오래 걸리고 그만큼 사용자가 화면을 보는 것(렌더링)이 지연된다. 또한 dom 트리가 아직 구성되지 않았기 때문에 script에 dom 요소를 조작하는 로직이 있다면 존재하지 않는 dom 요소에 접근하려고 했기 때문에 문제가 생길 수 있습니다. 다음으로 head가 아닌 body의 최하단에 script를 위치시키는 방법이 있습니다. html파싱이 모두 끝난 다음 script를 다운로드하고, 실행합니다. 이 경우 script를 다운로드하기 전 html파싱이 완료되기 때문에 사용자가 화면을 빨리 볼 수 있습니다. 하지만 만약 html이 script에 의존적(예를 들어 데이터 패칭해서 반영, 이벤트..) 라면 사용자가 화면을 보는 시점에 아직 완성되지 않은, 의미가 없는 페이지를 볼 수 있습니다. 이 문제들을 해결하기 위해서 몇 가지 방법을 생각해 볼 수 있는데, 먼저 DOMContentLoaded 이벤트를 사용하는 방법이 있습니다. 이 이벤트는 DOM 생성이 끝난 다음 트리거 됩니다. 그래서 head에 script를 두었을 때 이 방법을 사용하면 생성되지 않은 dom에 접근하는 문제를 해결할 수 있습니다. 비슷한 결로 window 객체의 onload 메서드를 오버라이딩 하는 방법이 있습니다. onload는 문서에 포함된 모든 리소스(img, style, script..)가 로드된 후 실행됩니다. 그리고 마지막 방법으로 body 하단에 script를 두었을 때의 스크립트 로드가 뒤늦게 일어나는 문제점을 해결하기 위해서 script 태그의 async, defer 속성을 사용해서 비동기적으로 스크립트를 로드하는 방법이 있습니다.

async 속성과 defer 속성의 차이점

원래는 script가 로드될 때 파싱이 멈추는데, async와 defer를 사용하면 스크립트 로드와 파싱이 병렬적으로 이루어지게 됩니다. 이렇게 되면 다운로드 시 페이지 렌더링을 막지 않지 않기 때문에 사용자가 화면을 빨리 볼 수 있습니다. 이런 async 속성과 defer 속성의 차이점은 두 가지가 있는데요. script의 실행 시점, 그리고 실행 순서에서 차이가 있습니다. async로 선언한 스크립트는 html를 파싱 하는 동시에 로드되고 이후 바로 실행시키는데, 실행시키는 동안에는 html 파싱이 멈추고, 실행이 완료된 이후 나머지 html을 파싱 한다. 또한 실행 순서에 있어서 먼저 로드된 스크립트가 먼저 실행됩니다. 이 경우 문제점은 html 파싱이 모두 완료되기 전에 스크립트가 실행될 수 있어서 존재하지 않는 dom에 접근하는 문제가 생길 수 있습니다. 또한 프로젝트가 스크립트 파일의 순서에 영향을 받으면(scope 등..) 문제가 생길 수 있습니다. defer로 넘어와서 실행 시점과 순서에 대해서 이야기를 해보면, defer는 async와 마찬가지로 html을 파싱 하는 동시에 script를 로드합니다. 다만 로드 이후 파싱을 멈추게 하고 스크립트를 실행시키는 async와 달리 defer는 html 파싱이 모두 완료된 이후 스크립트를 실행한다. 또한 defer는 script를 선언한 순서대로 실행을 시킵니다. 이렇게 되면 dom이 완성된 이후에 실행되기 때문에 존재하지 않는 dom에 접근할 가능성도 없습니다. 페이지를 좀 더 빨리 볼 수 있는 장점, 실행 순서에 영향을 받지도 않게 됩니다. 그래서 결론적으로 async는 DOM이나 다른 스크립트에 의존성이 없고, 실행 순서가 중요하지 않은 경우에 사용할 수도 있지만(예를 들어 구글 애널리틱스), async는 어찌되었든 렌더링을 방해하는 측면이 있기 때문에 웬만하면 defer를 사용하는 게 좋다고 생각합니다.

호이스팅에서 var 키워드와 let,const 키워드로 선언된 변수의 차이점

자바스크립트에서 변수는 선언, 초기화, 할당 단계를 거치게 됩니다. var와 let, const 키워드는 이 단계가 실행되는 시점이 다릅니다. 이 시점을 크게 소스코드의 평가와 실행으로 나눌 수 있습니다. var 키워드로 선언된 변수의 경우 런타임 이전 소스코드의 평가 과정에서 선언과 초기화가 이루어집니다. var 키워드로 선언된 변수는 평가 과정에서 실행 컨텍스트의 변수 객체에 변수가 등록되고, 메모리가 할당되면서 undefined로 초기화됩니다. 평가 과정에서 이미 초기화되었기 때문에 코드상에서 변수 선언문 이전에 변수에 접근해도 실행단계에서 에러가 발생하지 않고 undefined를 반환하게 됩니다. 이렇게 선언이 코드 실행보다 먼저 메모리에 저장되어 선언문이 맨 위로 끌어 올려진 것 같이 보이는 현상을 호이스팅이라고 하죠. 반면 let, const 키워드로 선언된 변수의 경우 평가단계에서 초기화가 아닌 선언 단계까지만 이루어집니다. 초기화는 코드 실행단계에서 다시 해당 선언문에 도달했을 때 이루어지기 때문에 변수 선언문 이전에 변수에 접근하면 참조 에러가 발생합니다. 이렇게 let,const 키워드로 선언한 변수는 스코프의 시작 지점부터 초기화 단계 시작 지점까지 변수를 참조할 수 없고, 이 구간을 일시적 사각지대(Temporal Dead Zone)이라고 부릅니다 정리하면, var 키워드와 let, const로 선언한 변수 모두 호이스팅이 발생하지만, var는 소스코드의 평가 과정에서 선언과 초기화가 이루어지고 let과 const는 선언 단계까지만 이루어지는 차이점이 있다고 할 수 있습니다.

호이스팅에서 함수 선언문과 함수 표현식의 차이점

함수는 함수 선언문으로 정의한 함수냐, 함수 표현식으로 정의한 함수냐에 따라 함수의 생성 시점이 다르기 때문에 다른 방식으로 호이스팅 됩니다. 함수 선언문으로 정의한 함수의 경우 런타임 이전에 해당 함수객체가 생성됩니다. 그리고 자바스크립트 엔진은 함수 이름과 동일한 이름의 식별자를 생성하고 생성된 함수 객체를 할당하게 됩니다. 변수로 치면 평가 단계에서 선언, 초기화, 할당이 모두 이루어진 셈이라고 할 수 있습니다. 따라서 함수 선언문으로 정의한 함수는 선언문 이전에 호출이 가능하고 이것을 함수 호스이팅이라고 합니다. 반면 함수 표현식은 var 변수처럼 런타임 이전에는 undefined로 초기화까지만 이루어지고 이후 런타임 때 함수 객체가 생성됩니다. 즉 변수 호이스팅이 발생합니다. 정리하면 함수 선언문은 평가 과정에서 함수 객체가 만들어지는 함수 호이스팅이 발생하고, 함수 표현식은 런타임 때 함수 객체가 만들어지는 변수 호이스팅이 발생한다고 할 수 있습니다.

Array와 LinkedList의 차이점

Array와 LinkedList는 메모리의 할당 방식과 할당 위치에서 차이가 있습니다. 배열에서 메모리는 선언 시 컴파일 타임에 할당이 됩니다. 이를 정적 메모리 할당이라고 합니다. 반면 Linkedlist는 새로운 node가 추가될 때 런타임에 메모리가 할당하고, 이를 동적 메모리 할당이라고 할 수 있습니다. 그래서 자바스크립트에서는 배열 사이즈를 명시적으로 지정하지 않아도 암묵적으로 메모리를 할당하고 해제해 주지만, 대부분의 언어에서는 배열의 size를 배열선언 시점에 지정해야 합니다. 할당 위치에 대해서는 array는 stack 영역에 메모리 할당이 이루어지게 되고 linkedlist는 head 영역에 할당됩니다. 다음으로 Array와 LinkedList는 데이터 접근 방식에서 차이가 있습니다. Array는 Random Access를 지원합니다. 요소들을 인덱스를 통해 직접 접근할 수 있습니다. 따라서 특정 요소에 접근하는 시간 복잡도를 빅 오 표기법으로 표시를 하면 O(1)이 됩니다. 반면Linkedlist는 Sequential Access, 순차적 접근을 지원합니다. 어떤 요소에 접근할 때 순차적으로 검색하며 찾아야 하고 따라서 특정 요소에 접근할 때 시간 복잡도는 O(N)이 됩니다. 접근 이외에도 삽입과 삭제가 있는데 이 경우 LinkedList가 조금 더 효율적입니다. Array는 접근해서 삽입, 삭제 후 요소들을 한 칸 식 shift 해야 하지만 LinkedList는 수정,삭제하고 앞뒤 주소만 연결해주면 됩니다. 따라서 데이터 접근, 탐색, 조회를 주로 할 경우에는 Array를 사용하고, 데이터 수정, 삽입, 삭제를 주로 할 경우에는 LinkedList를 사용하는 것이 좋습니다.

profile
요즘 인터렉티브한 웹에 관심이 많습니다.

0개의 댓글