본문 바로가기

FRONT-END/JAVASCRIPT

자바스크립트 HTTP GET 최적화

반응형

인터넷  환경에서의 HTTP GET 최적화

자바스크립트는 텍스트로 실행되는 스크립트 언어라서 프로그래밍하고 나면 그대로 사용자의 브라우저로 전송한다.

이처럼 HTTP 환경에서 데이터를 전송하는 방법의 하나가 GET이다.

웹페이지를 사용자에게 제공하기 전에 HTTP GET이 이루어지는데, GET으로 데이터를 전송하는 동안은 서비스가 제공되지 않거나 제한적이다.

이처럼 HTTP GET으로 발생할 수 있는 병목을 해소하려면 GET 용량을 줄이거나 GET  횟수를 줄여야 한다.

GET을 최적화하는 것이 웹페이지의 사용자 경험을 좌우하는 매우 중요한 단계이므로 특별히 신경써야한다.

특히 HTTP GET을 최적화하여 파일 전송 속도를 개선하는 것은 프론트엔드나 백엔드의 알고리즘을 최적화하는 것보다 처리는 훨씬 쉬우면서도 영향이 크기 때문에 가장 먼저 처리하면 좋다.


소스 미니피케이션으로 GET 용량 최소화

용량을 최소화하는 방법 중 대표적으로 미니피케이션이 있다.

자바스크립트 개발자 사이에서 일반화된 단어로, 소스를 최소화한다는 의미로 사용된다.

자바스크립트의 미니피케이션은 대표적으로 두 단계로 이루어진다.

첫 번째는 공백을 없애는 작업

두 번째는 불필요한 공백을 없애고 한줄로 길게 나타낸다.


모든 공백을 없애기  때문에 개행(\n)도 없어지고 들여쓰기도 모두 없어진다.

이렇게 하면 전체 소스는 길게 한줄이 되면서 가독성은 매우 나빠지지만, 전체적인 소스의 크키는 많이 줄어든다.

그래서 대형 사이트들의 자바스크립트 파일을 보면 공백없이 길게 한줄로 되어있다.


두번째 단계는 길게 정의된 변수명을 짧게 변경해서 전체적인 소스의 텍스트 길이를 줄이는 작업이다.

이 부분이 자바스크립트의 소스 크기를 줄이는데 아주 큰 역할을 한다.


index라고 정의된 변수를 a로 변경하면서 변수명이 4글자 줄었다. 이로써 해당 변수가 한번 사용할될 때마다 4바이트씩 절약 할수 있다.

그리고 sum 변수는 b로 정의하면서 변수가 사용될 때마다 2바이트씩 절약된다.

이러한 변경 내용은 자바스크립트가 복잡할수록 변수명을 다양하게 사용할수록 효과가 더 크다.

마찬가지로 대형 사이트들의 자바스크립트를 보면 변수명들이 알아보기 힘들게 짧은 이유도 용량을 줄이기 위해서이다.


미니피케이션 방법 이외에도 추가작업을 통해 소스를 더 작게 만든다.

1. 주석삭제

2. 산발적인 정의된 var를 하나로 통합해서 정의하도록 수정

3. if 구문 최적화 및 가능한 중괄호 생략

4. 상수로 통합할 수 있는 부분은 통합 또는 계산을 완료해서 소스에 적용

5. 기타 소스를 줄일수 있는 다양한 처리 로직


이러한 미니피케이션 과정을 거치고 나면 소스는 기존보다 매우 작아진다.


미니피케이션은 사용자가 웹페이지에 접속했을 때 내려받아야하는 용량을 최소화하여 사용자에게 웹페이지가 조금이라도 더 빠르게 보이게 하는 것이 가장 큰 목표이다.

jQuery 2.2 버전을 사용할 때 미니피케이션 소스의 용량은 86KB지만, 미니피케이션을 사용하지 않는 소스는 258KB이다.



CSS 미니피케이션

미니피케이션은 가장 영향이 큰 자바스크립트에서 사용하기 시작했다.

그러나 이제는 자바스크립트에만 국한하지 않고 CSS와 HTML에서도 많이 진행되어 인터넷 환경에서 파일을 내려받는 시간을 조금이라도 더 단축하는데 노력하고 있다.

CSS는 불 필요한 공백과 주석을 제거하고, 될수 있으면 세미콜론(;)을 생력하기도 한다.

같은 스타일이 통합될 수 있으면 통합해서 전체적인 텍스트 크기를 최소화하기도 한다.

원본 CSS는 1,1159byte이지만 미니피케이션 후에는 825byte로 약 30%의 용량 개선이 이루어졌다.,


HTML 미니피케이션

HTML은 자바스크립트 만큼 많은 텍스트로 구성되므로 내려받아야하는  HTML 파일을 크기를 최소화하면 좋다.

HTML에서 이루어지는 미니피케이션은 주석을 삭제하거나, 불필요한 속성들을 삭제하고  boolean 특성을 가진 속성들을 단순화 한다.


파일을 압축해서  GET 용량 최소화(gzip, deflate)

소스에서 불필요한 텍스트를 줄여서 성능을 개선할 수 있지만, 이 방법은 별도의 빌드 환경을 구축하거나 추가로 후처리 프로세스가 많이 들어가야하는 번거로움이 있따.

이보다 쉽게 용량을 줄일수 있는 방법이 바로 파일들을 압축하는 방법이다.

이 방법은 소스에서 개발자가 단독으로 수행할 수 없으며, 웹서버가  gzip 또는 deflate을 지원하도록 설정해야한다.


소스를 웹서버에서 압축하는 방식의 장점은 전송되는 용량을 줄임으로써 병목이 발생하는 인터넷 전송 구간을 최소화한다는 점이다.

파일을 압축해서 제공하면 기본적으로 미니피케이션을 통해서 줄이는 것보다 더 빠르고 효율적으로 용량을 줄일 수 있다.


파일을 서버에서 압축해서 제공하는 방식

gzip

gzip(GNU zip) 포맷사용

CRC-32 체크섬 사용

RFC 1952에 압축 방식 설명


deflate(zlib)

zlib 포맷 사용

ALDER-32 체크섬 사용

RFC 1950와  RFC 1951에 압축 방식 설명



GET요청 횟수 최소화(파일 합치기)

GET을 최적화하는 방법에는 파일별로 전송되는 용량을 개선하는 방법도 있지만, 내려받아야하는 파일의 수를 줄여서 GET 요청의 횟수를 줄이는 방법도 있다.

자바스크립트는 여러 파일을 사용하더라도 하나로 쉽게 합칠수 있으므로  GET 요청을 줄이는데 좋은 역할을 할 수 있다.

여러 개의 파일을 제공하는 경우 웹서버의 설정에 따라서 매번 세션을 열고  각각의 HTTP GET 요청 전문을 웹서버에 따로따로 전송해야한다.

하지만 여러 개의 요청을 하나로 합치면 이러한 작업을 한번만 해서 웹페이지 로드 속도를 개선 할 수 있고 사용자 경험도 향상 시킬수 있다.


자바스크립트 파일을 여러개 사용하는 것은 일반적인 웹사이트에서 매우 흔한 일이다.

이때 웹서버에서  TCP 세션을 유지하는 Keep-alive 설정이나 파일에 대한 캐시를 적절하게 사용하지 않는다면 GET 요청을 여러 번 보내는 것보다 자바스크립트 파일들을 하나로 합쳐서 처리하면 성능 개선의 효과를 쉽게 볼수 있다.

특히 자바사크립트나 CSS 파일들은 처리 로직상 파일이 합쳐진 것과 합쳐지지 않는 것에 큰 차이가 없으므로 쉽게 GET 요청의 횟수를 줄일 수 있다.

GET 요청 횟수를 줄이면 장점이 있다.

1. HTTP 요청과 응답을 여러번 주고 받는 것이 아니라 한번만 주고 받으면서 요청 응답 전문 처리를 최소화

2. Keep-alive가 설정되어 있지 않다면 TCP로 여러번 연결 함으로써 생기는 부하를 최소화

3. 특정 파일에 대한 내려받기 지연으로 인한 전체 페이지의 로드 지연 발생 확률 감소

4. GZIP 등의 압축처리를 여러 파일에 하는 것이 아니라 한번에 처리 기능


단점

1. 파일을 합치는 추가적인 빌드 단계

2. 특정 파일을 수정하는 경우  캐시 효율이 떨어짐

3. 특정 파일의 내려받기 실패가 전체 웹페이지의 로드 실패로 이어짐


장점과 비교해보면 충분히 하나의 파일로 합쳐서 제공하는 것을 고려할 수 있다.

단점 중에 파일을 하나로 합치는 추가 단계는 자바스크립트 파일을 배포하거나 gzip으로 먼저 사전 압축을 하거나 미니피케이션을 수행할 때 한 단계만 추가해서 진행하면된다.

그리고 캐시의 효율을 떨어뜨릴 정도로 자주 수정되는 자바스크립트 파일을 제외하고, 변경되지 않을 파일들만 합치면된다.

그리고 해당 파일의 내려받기 실패로 전체 웹페이지의 로드가 실패로 이어질수 있는 확률은 파일이 여러개로 나뉘어 있을 때도 마찬가지로 특정 기능이 정상 작동하지 않을 것이므로, 파일 내려받기 실패 자체를 리스크로 봐야한다.

따라서 자바스크립트 파이들을 하나의 파일로 합치면 GET 요청 횟수를 줄일수 있다.

자바스크립트를 내려받아 파싱하고 실행하는 데 성능을 개선 할 수 있다.


웹페이지에서 jQuery 를 사용하면 필요에 따라서는 jQuery의 소스 파일도 받아서 합쳐도 되지만, 공통적으로 많이 사용되는 라이리브러들은 CDN에 제공해주는 파일을 사용하는 것이 효율적일 확률이 높다.

왜냐하면 다른 사이트에서 같은 CDN에 있는 파일을 사용하면 그 사이트를 방문했다가 위의 사이트를 방문할 때 자동으로 캐시에 저장된 파일을 불러서 내려받는 속도를 최적화할 수 있기 때문이다.


그리고 floating_banner.js를 합치지 않는 이유는 웹페이지에 떠다니는 광고 배너를 표시해주는 자바스크립트라서 배너 수정 작업이 자주 발생할 것으로 예상했기 때문이다.

따라서 각 자바스크립트의 파일의 캐시를 효율적으로 사용하기 위해 따로 구분해 놓았다.

나중에 floating_banner.js 파일에 대하여 수정사항이 생기면 나머지 자바스크립트파일들에는 영향을 주지 않고 해당 floating_banner.js 파일만 다시 내려받으면 된다.


파일을 합칠 때도 주의할 점은 실행 순서가 중요한 내용들은 애초에 한 파일에 관리하도록 해서 파일의 순서가 역전되더라도 실행에 차질이 없어야한다.

그리고 될수 있으면 전역에 설정하는 strict 모드는 사용하지 않는다.

전역으로 strict 모드를 설정하면 이후에 합쳐지는 파일들도  strict 모드로 개발되어 있지 않다면 오류가 발생된다.

파일별로 함수안에 strict 모드를 설정하는 것이 좋다.


HTTP GET 요청으로 내려받아야 하는 파일의 수를 줄여서 HTTP GET의 횟수를 최적화하는 방안도 있지만, 웹서버의 환경설정으로 헤더에 캐시를 저장하도록 설정해서 애초에  HTTP  GET이 발생하지 않도록 하는 방법도 매우 좋은 성능 개선 방안이다.


이미지 파일 합치기

이미지파일은 비교적 크기가 큰 배경 이미지나 콘텐츠 이미지도 그렇지만 크기가 작고  종류가 다양한 작은 아이콘들도 이미지 파일 하나당 한 개의 GET 요청을 발생시킨다.

배경 이미지나 콘텐츠 이미지들은 웹페이지의 내용 변경에 따라 자주 변경될 수 있지만, 아이콘 등과 같은 작은 이미지들은 자주 변경되지 않으므로 하나의 이미지로 합치는 것이 효율적인 경우도 많다.

GET 요청의 최적화도 있지만, 각 이미지가 아니라 합쳐놓은 큰 이미지에 대한 캐시만 관리하면 된다는 장점도 있다.

여러 개의 이미지를 하나의 이미지파일로 합치는 것을 이미지 스프라이트 라고 한다.

<img> 태그에서  src 속성은 없어지고 모든 <img> class 속성을 사용하여 <style>에서 class별로 처리하여 큰 이미지의 위치를 사용한다.

특히 이미지가 많은 페이지에서는 이미지마다 발생할 GET 요청의 횟수가 줄어 페이지 로드 시간이 향상된다.

웹서버의 캐시를 설정하는 경우 하나의 이미지에 대해서만 캐시를 관리하면 되므로 캐시관리에도 유리하다.


캐시설정

웹서버에서 캐시를 설정하는 것은 정적인 웹페이지에서 웹서버에 대한 트래픽 부담과 사용자 경험을 비약적으로 높일 수 있는 설정이다.

여기서 캐시와 관련된  HTTP 헤더는 대표적으로 Expires가 있다. Expires 헤더는 응답 헤더에 포함되는 내용으로 웹서버에서 현재 파일이 언제까지 유효한지 알려주는 역할을 한다.

Expires를 설정하면 브라우저에서는 캐시로 해당 파일을 저장하고 있다가 Expires날짜가 지나기 전에 다시 같은 파일에 접근하고자 할 때 웹서버로 요청을 보내느 것이 아니라, 저장하고 있는 파일을 그대로 사용한다.

이 경우에는 웹서버로 HTTP GET 요청을 보내지 않기 때문에 추가적인 TCP 연결이나 HTTP 요청/응답 전문에 대한 처리가 필요없다.

따라서 사용자가 두번째로 웹페이지에 방문하면 사용자 경험이 크게 향상된다.


아파치 웹서버에서 Expires 헤더를 설정하는 방법

<IfModule mod_expires.c>

ExpiresActive On

ExpiresDefault "access plus 3 hours"


<FilesMatch "\.(jpg|jpeg|png|gif|swf|ico)$">

ExpiresDefault "access plus 1 week"

</FilesMatch>


<FilesMatch "\.(txt|xml|js}css)$">

ExpiresDefault "access plus 1 day"

</FilesMatch>


</IfModule>

Expires 헤더의 기본값은 현재 시각에 3시간을 더한 값으로 설정하고 jpg 등의 이미지 파일은 1주일기간동안 캐시를 저장하도록 하고, js나 css 파일들은 하루동안만 캐시를 유지하도록 명시하는 것이다.


Expires를 설정하면 웹서버에서 아예 요청이 들어오지 않게 돼서 사용자 경험과 웹페이지 로드 속도 모두 좋아지지만, 웹페이지가 자주 수정되고 변경되는 경우에는 Expires가 지나거나 브라우저의 캐시를 지우기 전까지는 알 방법이 없다.

따라서 이러한 이슈를 해결하기 위한 헤더가 바로 ETag이다 .

ETag 헤더는 파일별로 유일한 값을 가지는 해시 값을 헤더로 보관하고 있으며, 브라우저에서는 현재 가지고 있는 파일의 정보를 ETag 헤더에 넣어 웹서버로 보낸다.

이후 웹서버에서는 웹서버에 있는 파일 ETag 값을 비교해서 같으면 HTTP 304 Not modiified를 응답 전문으로 보낸다.

브라우저가 HTTP 304 Not Modified를 수신하면 파일이 수정되지 않았음을 인지하고 별도로 파일을 내려받지 않고 기존에 가지고 있던 파일을 그대로 사용한다.


이처럼 캐시를 이용하여 HTTP GET을 최적화하는 방법이 있으며, 작은 이미지나 그림, 아이콘 같은 경우에는 여러 개의 작은 이미지를 하나의 이미지로 합쳐서 올려놓고 각각 필요한 부분을 잘라서 사용하는 CSS 스프라이트도 유용하다.


출처-속깊은 자바스크립트 양성익 지음


반응형