no_mkd
서문
영문 원본 링크이며, 본문에 부족한 점이 있다면 지적해 주세요. 즉시 수정하겠습니다.
목차 (7개 카테고리, 총 35가지):
- [콘텐츠] HTTP 요청 수를 최소화하라
- [서버] CDN(Content Delivery Network)을 사용하라
- [서버] Expires 또는 Cache-Control HTTP 헤더를 추가하라
- [서버] 컴포넌트를 Gzip으로 압축하라
- [CSS] 스타일시트를 상단에 배치하라
- [JS] 스크립트를 하단에 배치하라
- [CSS] CSS Expression 사용을 피하라
- [JS, CSS] 자바스크립트와 CSS를 외부 파일로 분리하라
- [콘텐츠] DNS 조회를 줄여라
- [JS, CSS] 자바스크립트와 CSS를 압축(Minify)하라
- [콘텐츠] 리다이렉트를 피하라
- [JS] 중복된 스크립트를 제거하라
- [서버] ETags를 설정하라
- [콘텐츠] Ajax를 캐싱 가능하게 하라
- [서버] 버퍼를 일찍 비워라(Flush)
- [서버] Ajax 요청에 GET 방식을 사용하라
- [콘텐츠] 컴포넌트 후행 로드(Lazy Load)를 활용하라
- [콘텐츠] 컴포넌트 사전 로드(Preload)를 활용하라
- [콘텐츠] DOM 요소의 수를 줄여라
- [콘텐츠] 컴포넌트를 여러 도메인으로 분산하라
- [콘텐츠] iframe 사용을 최소화하라
- [콘텐츠] 404 오류를 방지하라
- [쿠키] 쿠키 크기를 줄여라
- [쿠키] 쿠키가 없는 도메인에 컴포넌트를 배치하라
- [JS] DOM 접근을 최소화하라
- [JS] 스마트한 이벤트 핸들러를 사용하라
- [CSS] @import 대신 <link>를 선택하라
- [CSS] 필터(Filter) 사용을 피하라
- [이미지] 이미지를 최적화하라
- [이미지] CSS Sprite를 최적화하라
- [이미지] HTML에서 이미지 크기를 조절하지 마라
- [이미지] 작고 캐싱 가능한 favicon.ico를 사용하라
- [모바일] 모든 컴포넌트 크기를 25K 이하로 유지하라
- [모바일] 컴포넌트를 하나의 복합 문서로 묶어라
- [서버] 이미지 src 속성을 비워두지 마라
번역: 웹사이트 속도를 높이는 베스트 프랙티스
사이트 속도를 높이는 베스트 프랙티스를 7개 카테고리, 총 35가지로 정리했습니다.
1. HTTP 요청 수를 최소화하라
분류: 콘텐츠
최종 사용자 응답 시간의 80%는 프론트엔드에서 소요됩니다. 대부분의 시간은 페이지의 다양한 컴포넌트(이미지, 스타일시트, 스크립트, Flash 등)를 다운로드하는 데 사용됩니다. 컴포넌트 수를 줄이면 자연스럽게 페이지의 HTTP 요청 수가 줄어듭니다. 이것이 페이지 속도를 높이는 핵심입니다.
페이지 컴포넌트 수를 줄이는 한 가지 방법은 페이지 디자인을 단순화하는 것입니다. 하지만 복잡한 페이지를 구축하면서 동시에 응답 시간을 단축할 방법이 있을까요? 네, 두 마리 토끼를 잡을 방법이 있습니다.
파일 병합은 모든 스크립트를 하나의 파일로 합쳐 요청 수를 줄이는 방식입니다. 물론 CSS도 동일하게 병합할 수 있습니다. 각 페이지마다 스크립트와 스타일이 다르다면 병합 작업이 번거로울 수 있지만, 이를 배포 프로세스의 일부로 포함하면 응답 시간을 효과적으로 단축할 수 있습니다.
CSS Sprites는 이미지 요청 수를 줄이는 가장 선호되는 방식입니다. 배경 이미지들을 하나의 이미지로 통합한 뒤, CSS의 background-image와 background-position 속성을 사용하여 표시할 부분을 지정합니다.
이미지 맵은 여러 장의 이미지를 하나의 이미지로 합치는 방식입니다. 전체 크기는 같지만 요청 수를 줄여 페이지 로딩 속도를 높입니다. 이미지 맵은 내비게이션 바와 같이 이미지가 연속적일 때만 유용합니다. 좌표 설정 과정이 지루하고 오류가 발생하기 쉬우며 내비게이션으로 사용하기에도 불편함이 있어 권장되는 방식은 아닙니다.
인라인 이미지(Base64 인코딩)는 data: URL 패턴을 사용하여 이미지를 페이지에 직접 포함합니다. 이는 HTML 파일의 크기를 키우므로, 인라인 이미지를 캐싱된 스타일시트에 포함하는 것이 페이지가 너무 무거워지는 것을 방지하는 좋은 방법입니다. 하지만 현재 모든 주요 브라우저가 인라인 이미지를 완벽하게 지원하지는 않습니다.
HTTP 요청 수를 줄이는 것은 사이트의 첫 방문 속도를 높이는 중요한 원칙입니다. Tenni Theurer의 블로그 Browser Cache Usage - Exposed!에 따르면, 방문자의 40%~60%는 캐시가 비어 있는 상태로 사이트를 방문합니다. 따라서 첫 방문 속도를 높이는 것은 사용자 경험을 향상시키는 데 매우 중요합니다.
2. CDN(Content Delivery Network)을 사용하라
분류: 서버
사용자와 서버 간의 물리적 거리도 응답 시간에 영향을 미칩니다. 콘텐츠를 지리적으로 분산�� 여러 서버에 배포하면 사용자가 페이지를 더 빨리 로드할 수 있습니다. 하지만 구체적으로 어떻게 해야 할까요?
지리적 분산을 구현하는 첫 번째 단계는 분산 구조에 맞게 웹 애플리케이션을 재설계하려고 하지 않는 것입니다. 애플리케이션에 따라 구조 변경에는 세션 상태 동기화나 서버 간 데이터베이스 트랜잭션 복제와 같은 까다로운 작업이 포함될 수 있습니다. 이러한 난제 때문에 사용자와 콘텐츠 사이의 거리를 좁히려는 제안이 지연되거나 불가능해질 수 있습니다.
최종 사용자 응답 시간의 80%~90%는 이미지, 스타일, 스크립트, Flash 등의 컴포넌트를 다운로드하는 데 사용된다는 성능의 황금 법칙을 기억하세요. 처음부터 애플리케이션 구조를 재설계하기보다 정적 콘텐츠를 먼저 분산하는 것이 좋습니다. 이는 응답 시간을 크게 단축할 뿐만 아니라 CDN의 효과를 입증하기도 더 쉽습니다.
콘텐츠 전송 네트워크(CDN)는 지리적으로 분산된 웹 서버 그룹으로, 사용자에게 콘텐츠를 더 효율적으로 전송하는 데 사용됩니다. 일반적으로 네트워크 거리(예: 최소 홉 수 또는 가장 빠른 응답 시간)를 기준으로 전송 서버를 선택합니다.
일부 거대 IT 기업은 자체 CDN을 보유하고 있지만, Akamai Technologies, EdgeCast, level3와 같은 CDN 서비스 제공업체를 이용하는 것이 경제적입니다. 스타트업이나 개인 사이트에게 CDN 비용은 부담스러울 수 있지만, 사용자 층이 커지고 글로벌화된다면 빠른 응답 시간을 위해 CDN을 도입할 필요가 있습니다. 야후의 경우, 정적 콘텐츠를 웹 서버에서 CDN(제3자 서비스 및 야후 자체 CDN 포함)으로 옮김으로써 응답 시간을 20% 이상 단축했습니다. CDN 도입은 비교적 간단한 코드 변경만으로 사이트 응답 속도를 획기적으로 높일 수 있는 방법입니다.
3. Expires 또는 Cache-Control HTTP 헤더를 추가하라
분류: 서버
이 규칙은 두 가지 측면이 있습니다:
- 정적 컴포넌트:
Expires헤더에 먼 미래의 시간을 설정하여 영구적으로 유효하게 함 - 동적 컴포넌트: 적절한
Cache-Control헤더를 사용하여 브라우저가 조건부 요청을 하도록 함
웹 디자인이 화려해질수록 페이지에는 더 많은 스크립트, 이미지, Flash가 포함됩니다. 첫 방문자는 여전히 몇 번의 HTTP 요청을 해야 하겠지만, 유효 기간 설정을 통해 컴포넌트를 캐싱 가능하게 만들면 이후 페이지 탐색 시 불필요한 요청을 피할 수 있습니다. Expires 헤더는 주로 이미지에 사용되지만, 스크립트, 스타일시트, Flash를 포함한 모든 컴포넌트에 적용해야 합니다.
브라우저(및 프록시)는 캐시를 사용하여 요청 수와 크기를 줄여 페이지를 더 빨리 로드합니다. 웹 서버는 Expires 응답 헤더를 통해 클라이언트에게 컴포넌트가 얼마나 오래 캐싱되어야 하는지 알려줍니다. 먼 미래의 시간을 설정하면 브라우저에 해당 응답이 지정된 날짜 전까지는 변하지 않을 것임을 알릴 수 있습니다.
Expires: Thu, 15 Apr 2010 20:00:00 GMT
Apache 서버를 사용하는 경우, ExpiresDefault 지시어를 사용하여 현재 날짜로부터의 상대적인 유효 기간을 설정할 수 있습니다. 다음 예시는 요청 시간으로부터 10년의 유효 기간을 설정합니다.
ExpiresDefault "access plus 10 years"
먼 미래의 시간을 유효 기간으로 설정했다면, 컴포넌트가 변경될 때 파일명을 즉시 수정해야 한다는 점을 유의하세요. 야후에서는 보통 빌드 프로세스의 일부로 파일명에 버전 번호를 포함합니다. 예: yahoo_2.0.6.js
Expires 헤더 설정은 사용자가 이미 사이트를 방문한 적이 있을 때만 효과가 나타납니다. 첫 방문자나 캐시가 비워진 경우에는 요청 수에 영향을 미치지 않습니다. 따라서 이 성능 향상은 캐싱된 컴포넌트를 가진 사용자의 재방문 빈도에 달려 있습니다. 야후의 조사에 따르면 캐싱된 페이지 뷰(PV)가 75%~85%를 차지했습니다. Expires 헤더를 통해 캐싱된 컴포넌트 수를 늘리면 이후 방문 시 네트워크 연결을 통해 단 1바이트도 더 보낼 필요가 없게 됩니다.
4. Gzip 컴포넌트
분류: 서버
프론트엔드 엔지니어는 네트워크를 통해 전송되는 HTTP 요청 및 응답 시간을 눈에 띄게 단축할 방법을 찾을 수 있습니다. 최종 사용자의 대역폭 속도, ISP, 교환 지점과의 거리 등은 통제할 수 없지만, 응답의 크기를 줄여 응답 시간을 단축할 수는 있습니다.
HTTP/1.1부터 웹 클라이언트는 압축을 지원하는 Accept-Encoding 요청 헤더를 갖게 되었습니다.
Accept-Encoding: gzip, deflate
웹 서버가 이 헤더를 확인하면 클라이언트가 나열한 방식 중 하나로 응답을 압축합니다. 그리고 Content-Encoding 응답 헤더를 통해 클라이언트에 알립니다.
Content-Encoding: gzip
Gzip은 현재 가장 일반적이고 효율적인 압축 방법으로, GNU 프로젝트에 의해 개발되었으며 RFC 1952로 표준화되었습니다. 가끔 보이는 또 다른 형식은 deflate이지만 효율이 낮고 흔하지 않습니다.
Gzip은 일반적으로 응답 크기를 약 70% 정도 줄여주며, 현재 약 90%의 브라우저가 gzip 전송을 지원합니다. Apache 서버의 경우 버전에 따라 gzip 설정 모듈이 다릅니다. Apache 1.3은 mod_gzip을, Apache 2.x는 mod_deflate 모듈을 사용합니다.
브라우저나 프록시의 특정 요인으로 인해 압축된 내용이 올바르게 전달되지 않는 경우가 있을 수 있습니다. 다행히 구형 브라우저가 도태되면서 이러한 상황은 줄어들고 있으며, Apache 모듈은 적절한 Vary 응답 헤더를 자동으로 추가하여 이를 해결해 줍니다.
서버는 파일 유형에 따라 gzip 압축 여부를 결정하지만 이는 매우 제한적일 수 있습니다. 대부분의 사이트가 HTML 파일은 압축하지만 스크립트와 스타일시트는 놓치는 경우가 많습니다. 사실 XML과 JSON을 포함한 모든 텍스트 콘텐츠는 압축 가능합니다. 이미지와 PDF는 이미 자체적으로 압축되어 있으므로 gzip 압축을 하면 CPU만 낭비하고 오히려 크기가 커질 수도 있습니다.
가능한 한 많은 텍스트 컴포넌���에 gzip 압축을 적용하는 것은 페이지 크기를 줄이고 사용자 경험을 높이는 가장 간단한 방법입니다.
5. 스타일시트를 상단에 배치하라
분류: CSS
야후의 성능 연구에 따르면, 스타일시트를 문서의 HEAD 섹션에 두면 페이지가 더 빨리 로드되는 것처럼 보입니다. 스타일시트가 상단에 있으면 페이지가 점진적으로 렌더링(Progressive Rendering)될 수 있기 때문입니다.
성능에 관심 있는 프론트엔드 엔지니어는 페이지가 점진적으로 렌더링되기를 원합니다. 즉, 브라우저가 이미 로드된 내용을 최대한 빨리 표시하도록 하여 사용자에게 피드백을 주어야 합니다. 이는 페이지 내용이 많거나 사용자 네트워크가 느릴 때 특히 중요합니다. 사용자에게 진행 상태를 보여주는 것의 중요성은 이미 널리 연구 및 기록되어 왔습니다. HTML 페이지 자체가 진행 표시기 역할을 하는 셈입니다. 브라우저가 헤더, 내비게이션 바, 로고 등을 차례로 보여주면 사용자는 로딩을 기다리는 동안 긍정적인 경험을 하게 됩니다.
IE를 포함한 많은 브라우저에서 스타일시트가 문서 하단에 있으면 점진적 렌더링이 차단됩니다. 스타일 변경으로 인한 재그리기(Repaint)를 방지하기 위해 렌더링을 멈추기 때문이며, 사용자는 빈 화면만 보게 됩니다.
HTML 공식 문서에는 스타일시트가 HEAD 내부에 있어야 한다고 명시되어 있습니다. 빈 화면이나 스타일이 입혀지지 않은 콘텐츠(FOUC)는 피해야 합니다. 이상적인 해결책은 표준을 따라 스타일시트를 HEAD 섹션에 두는 것입니다.
6. 스크립트를 하단에 배치하라
분류: 자바스크립트
스크립트는 병렬 다운로드를 차단합니다. HTTP/1.1 공식 문서는 브라우저가 호스트당 병렬 다운로드 수를 2개로 제한할 것을 권장합니다. 이미지가 여러 호스트에 있다면 더 많이 병렬로 다운로드할 수 있지만, 스크립트가 다운로드되는 동안 브라우저는 다른 호스트의 리소스일지라도 다운로드를 시작하지 않습니다.
가끔 스크립트를 하단으로 옮기기 어려울 때가 있습니다. 예를 들어 document.write를 사용하여 내용을 삽입하는 스크립트는 위치를 옮길 수 없습니다. 또한 스코프 문제가 발생할 수도 있지만, 대부분의 경우 이러한 문제는 해결 가능합니다.
흔히 제안되는 방식은 DEFER 속성을 사용하는 것입니다. 이는 스크립트에 document.write가 포함되지 않았음을 의미하며 브라우저에 렌더링을 계속해도 좋다는 힌트를 줍니다. 안타깝게도 Firefox는 이 속성을 지원하지 않으며 IE에서의 동작도 완벽하지 않을 수 있습니다. 스크립트를 하단으로 옮길 수만 있다면 페이지 로딩 속도를 더 높일 수 있습니다.
7. CSS Expression 사용을 피하라
분류: CSS
CSS Expression을 사용하여 CSS 속성을 동적으로 설정하는 방식은 강력하지만 위험합니다. IE5부터 지원되었으나 IE8부터는 권장되지 않습니다. 예를 들어 시간마다 배경색을 바꾸기 위해 다음과 같이 사용할 수 있습니다.
background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );
위 코드에서 expression 메서드는 자바스크립트 표현식을 인자로 받습니다. 속성값은 표현식의 계산 결과로 설정됩니다. 이 방식은 다른 브라우저에서는 무시되므로 IE 전용 기능을 구현할 때만 쓰였습니다.
Expression의 가장 큰 문제는 예상보다 훨씬 자주 계산된다는 점입니다. 페이지 렌더링이나 크기 조절 시뿐만 아니라 페이지 스크롤이나 마우스 이동 시에도 다시 계산됩니다. 카운터를 달아 확인해 보면 마우스 이동 한 번에 만 번 이상의 재계산이 발생하기도 합니다.
재계산을 줄이는 한 가지 방법은 일회성 표현식을 사용하여 첫 계산 후 값을 고정하는 것이지만, 동적인 스타일 설정이 지속적으로 필요하다면 차라리 이벤트 핸들러를 사용하는 것이 낫습니다. 만약 꼭 써야 한다면 수천 번 재계산되어 전체 페이지 성능에 악영향을 미칠 수 있음을 기억해야 합니다.
8. 자바스크립트와 CSS를 외부 파일로 분리하라
분류: 자바스크립트, CSS
많은 성능 원칙이 외부 컴포넌트 관리에 관한 것이지만, 그전에 자바스크립트와 CSS를 외부 파일로 둘 것인지 페이지 내부에 쓸 것인지(Inline) 근본적인 질문을 해야 합니다.
실제로는 외부 파일을 사용하는 것이 페이지 속도를 높이는 데 유리합니다. 외부 파일은 브라우저에 의해 캐싱되기 때문입니다. 인라인 방식은 HTML 요청 때마다 리소스를 함께 다운로드해야 하므로 요청 수는 줄지만 HTML 크기가 커집니다. 반면 외부 파일로 분리하고 캐싱을 활용하면 HTML 크기도 줄이고 추가적인 HTTP 요청도 발생하지 않습니다.
핵심 요인은 외부 파일의 캐싱 빈도와 페이지 요청 수 간의 관계입니다. 이를 수치화하기는 어렵지만 지표를 통해 측정할 수 있습니다. 사용자가 한 세션 동안 여러 페이지를 방문한다면 동일한 스크립트와 스타일시트를 재사용할 수 있으므로 외부 파일 캐싱의 이점이 극대화됩니다.
대부분의 사이트에는 외부 파일로 배포하는 것이 최선입니다. 유일한 예외는 야후 홈이나 마이 야후처럼 세션당 방문 횟수가 적은 첫 페이지입니다. 이런 경우 인라인 방식이 더 빠른 응답 시간을 제공할 수 있습니다.
전형적인 사이트의 경우, 홈 페이지 로드 완료 후 외부 파일을 동적으로 로드하는 기술을 사용하여 이후 방문할 페이지에 필요한 리소스를 미리 캐싱해 두는 전략을 취할 수 있습니다.
9. DNS 조회를 줄여라
분류: 콘텐츠
DNS는 호스트 이름과 IP 주소를 매핑합니다. 브라우저에 www.yahoo.com을 입력하면 DNS 리졸버에 접속하여 IP 주소를 받아옵니다. DNS 조회에는 약 20~120ms가 소요되며, 조회가 완료되기 전까지 브라우저는 아무것도 다운로드할 수 없습니다.
DNS 정보는 ISP나 로컬 네트워크 서버, 그리고 개인 컴퓨터에 캐싱됩니다. 윈도우의 "DNS Client" 서비스와 같은 OS 레벨뿐만 아니라 대부분의 브라우저도 자체 캐시를 가지고 있습니다. 브라우저 캐시에 기록이 남아 있는 동안은 OS에 쿼리를 보내지 않습니다.
IE는 기��적으로 30분 동안 캐싱하며, Firefox는 1분 동안 캐싱합니다. (Fasterfox와 같은 플러그인을 쓰면 시간을 더 늘릴 수도 있습니다.)
캐시가 비어 있는 경우 DNS 조회 횟수는 페이지에 포함된 서로 다른 호스트 이름의 수와 같습니다. 호스트 이름을 줄이면 DNS 조회를 줄일 수 있습니다.
하지만 호스트 이름을 너무 줄이면 병렬 다운로드 성능이 떨어집니다. 제 원칙은 컴포넌트를 2~4개의 호스트 이름으로 분산하는 것입니다. 이는 DNS 조회 비용과 병렬 다운로드 효율 간의 적절한 타협점입니다.
10. 자바스크립트와 CSS를 압축(Minify)하라
분류: 자바스크립트, CSS
압축은 코드에서 불필요한 문자를 제거하여 크기를 줄이고 로딩 속도를 높이는 작업입니다. 모든 주석과 불필요한 공백(스페이스, 줄바꿈, 탭)을 제거합니다. 가장 널리 쓰이는 도구는 JSMin과 YUI Compressor가 있습니다.
난독화(Obfuscation)는 더 복잡한 최적화 방식으로, 코드 크기를 더 많이 줄여주지만 버그가 발생할 위험이 압축보다 큽니다. 상위 사이트 조사에 따르면 압축은 약 21%, 난독화는 약 25%의 크기 절감 효과가 있었습니다.
외부 파일뿐만 아니라 인라인 <script>와 <style> 블록도 압축 대상입니다. Gzip 모듈을 사용하더라도 사전에 압축을 진행하면 5% 이상의 추가 절감 효과를 볼 수 있습니다.
11. 리다이렉트를 피하라
분류: 콘텐츠
리다이렉트는 301 및 302 상태 코드를 사용합니다. 다음은 301 상태 코드 헤더의 예입니다.
HTTP/1.1 301 Moved Permanently
Location: http://example.com/newuri
Content-Type: text/html
브라우저는 Location에 명시된 URL로 자동 이동합니다. 리다이렉트에 필요한 정보는 헤더에 있으며 응답 본문은 보통 비어 있습니다. 리다이렉트는 사용자 경험을 저하시킵니다. HTML 문서 도달 전까지 렌더링도 시작되지 않고 컴포넌트 다운로드도 지연되기 때문입니다.
가장 흔하고 낭비적인 리다이렉트 중 하나는 URL 끝에 슬래시(/)가 빠진 경우입니다. .../astrology로 접속하면 .../astrology/로 리다이렉트되는 301 응답이 발생합니다. Apache에서는 Alias나 mod_rewrite 등으로 이를 방지할 수 있습니다.
도메인 변경 시 리다이렉트가 필요하다면 CNAME 레코드와 Alias 등을 결합하여 사용하는 것이 사용자 경험 측면에서 더 좋습니다.
12. 중복된 스크립트를 제거하라
분류: 자바스크립트
한 페이지에 동일한 스크립트 파일이 중복 포함되면 성능에 악영향을 줍니다. 이는 불필요한 HTTP 요청을 발생시키고 쓸데없는 자바스크립트 실행 시간을 소모하게 합니다.
IE의 경우 캐싱되지 않는 외부 스크립트가 두 번 포함되면 로딩 시 요청을 두 번 보냅니다. 캐싱이 가능하더라도 페이지 새로고침 시 추가 요청이 발생할 수 있습니다. 또한 브라우저와 상관없이 중복된 스크립트 실행은 CPU 자원을 낭비합니다.
중복 포함을 방지하기 위해 템플릿 시스템에서 스크립트 관리 모듈을 구현하는 것이 좋습니다. PHP의 경우 insertScript 같은 함수를 만들어 의존성 체크와 버전 번호 관리를 함께 처리할 수 있습니다.
13. ETags를 설정하라
분류: 서버
Entity Tags(ETags)는 브라우저 캐시의 컴포넌트와 서버의 컴포넌트가 일치하는지 확인하는 메커니즘입니다. 마지막 수정일(Last-Modified)보다 유연한 검증 방식을 제공합니다. 서버는 ETag 응답 헤더를 통해 고유 식별자를 전달합니다.
HTTP/1.1 200 OK
Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
ETag: "10c24bc-4ab-457e1c1f"
Content-Length: 12195
브라우저가 컴포넌트를 검증해야 할 때 If-None-Match 헤더에 ETag를 실어 보냅니다. 일치하면 304 코드를 반환하여 본문 전송을 생략합니다.
ETags의 문제는 특정 서버에 종속적인 값으로 생성되는 경우가 많다는 점입니다. 여러 대의 서버가 요청을 처리하는 환경(Server Cluster)에서 사용자가 다른 서버로부터 컴포넌트 일치 여부를 검증하려 할 때, 기본 설정된 Apache나 IIS의 ETag 형식(inode 사용 등) 때문에 일치하지 않는 것으로 판정되어 불필요한 200 응답과 데이터 전송이 발생할 수 있습니다.
서버가 여러 대라면 아예 ETags를 제거하고 Last-Modified 방식만 사용하는 것이 나을 수 있습니다. ETags를 제거하면 요청 및 응답 헤더의 크기도 줄어듭니다.
14. Ajax를 캐싱 가능하게 하라
분류: 콘텐츠
Ajax는 비동기 요청을 통해 즉각적인 피드백을 주지만, "비동기"가 반드시 "즉시"를 의미하지는 않습니다. 성능 최적화를 위해 Ajax 응답 역시 캐싱 가능하게 만드는 것이 중요합니다. Expires 또는 Cache-Control 헤더 설정을 포함하여 Gzip 압축, DNS 조회 감소, 코드 압축, 리다이렉트 방지 등의 규칙이 Ajax에도 동일하게 적용됩니다.
예를 들어 자동 완성 기능을 위한 주소록 데이터 Ajax 요청 시, 데이터가 변경되지 않았다면 캐시에서 읽어오도록 해야 합니다. URL에 타임스탬프 파라미터(예: &t=...)를 추가하여 데이터가 변경되었을 때만 새로운 요청이 발생하도록 관리할 수 있습니다.
15. 버퍼를 일찍 비워라(Flush)
분류: 서버
서버가 HTML 페이지를 구성하는 데 보통 200~500ms가 소요됩니다. PHP의 flush() 함수를 사용하면 이미 준비된 일부 HTML 응답을 브라우저에 미리 보낼 수 있습니다. 이를 통해 브라우저는 서버가 나머지 본문을 구성하는 동안 스타일시트나 스크립트 같은 컴포넌트를 병렬로 다운로드하기 시작할 수 있습니다.
이상적인 위치는 HEAD 섹션 바로 다음입니다. HTML의 HEAD 부분은 생성이 빠르고 주요 CSS/JS 파일이 선언되어 있어 브라우저의 병렬 로딩을 조기에 시작시킬 수 있습니다.
16. Ajax 요청에 GET 방식을 사용하라
분류: 서버
야후 메일 팀의 조사에 따르면 XMLHttpRequest 사용 시 POST 방식은 헤더를 먼저 보내고 데이터를 나중에 보내는 두 단계 과정을 거칩니다. 반면 GET 방식은 하나의 TCP 패킷으로 전송되는 경우가 많아 더 효율적입니다. 다만 IE의 URL 길이 제한(2K) 때문에 데��터가 너무 많다면 POST를 써야 합니다.
17. 컴포넌트 후행 로드(Lazy Load)를 활용하라
분류: 콘텐츠
페이지 초기 렌더링에 반드시 필요한 것이 무엇인지 자문해 보세요. 나머지는 나중에 로드해도 됩니다. 드래그 앤 드롭 라이브러리나 애니메이션 스크립트, 보이지 않는 영역의 이미지 등은 초기 렌더링 이후에 로드해도 무방합니다. YUI Image Loader나 YUI Get 유틸리티가 도움이 될 수 있습니다.
18. 컴포넌트 사전 로드(Preload)를 활용하라
분류: 콘텐츠
사전 로드는 브라우저가 유휴 상태일 때 나중에 쓰일 리소스를 미리 요청하는 방식입니다. 무조건적 사전 로드(다음 페이지에 쓰일 리소스), 조건부 사전 로드(사용자 액션에 근거한 예측 로드), 혹은 새로운 사이트 디자인 공개 전 미리 리소스를 다운로드하는 방식 등이 있습니다.
19. DOM 요소의 수를 줄여라
분류: 콘텐츠
복잡한 페이지는 다운로드할 바이트가 많고 JS의 DOM 접근 속도도 떨어뜨립니다. 불필요한 중첩 테이블이나 레이아웃만을 위한 <div> 남발을 피하고 시맨틱한 마크업을 사용하세요. 야후 홈 페이지는 매우 복잡하지만 요소 수가 700개 미만으로 관리되고 있습니다.
20. 컴포넌트를 여러 도메인으로 분산하라
분류: 콘텐츠
컴포넌트를 여러 도메인에 나누어 배치하면 브라우저의 병렬 다운로드 효율을 높일 수 있습니다. 하지만 DNS 조회 비용 때문에 2~4개 정도의 도메인을 사용하는 것이 적절합니다.
21. iframe 사용을 최소화하라
분류: 콘텐츠
iframe은 외부 콘텐츠나 보안 샌드박스 등에는 유용하지만 생성 비용이 크고 페이지 로딩을 차단할 수 있으며 시맨틱하지 않으므로 주의해서 사용해야 합니다.
22. 404 오류를 방지하라
분류: 콘텐츠
불필요한 404 응답은 서버 자원을 낭비하고 사용자 경험을 해칩니다. 특히 외부 자바스크립트 파일에 대한 404는 병렬 다운로드를 차단할 뿐만 아니라 브라우저가 쓸모없는 내용을 파싱하게 만듭니다.
23. 쿠키 크기를 줄여라
분류: 쿠키
쿠키 정보는 매 요청마다 서버와 브라우저 사이를 오갑니다. 불필요한 쿠키를 삭제하고 크기를 최소화하여 전송 효율을 높이세요. 적절한 도메인 레벨과 유효 기간 설정도 중요합니다.
24. 쿠키가 없는 도메인에 컴포넌트를 배치하라
분류: 쿠키
이미지와 같은 정적 파일 요청 시 불필요한 쿠키 전송을 막기 위해 쿠키가 설정되지 않은 별도 도메인(예: static.example.org 또는 아예 다른 도메인)을 사용하는 것이 좋습니다.
25. DOM 접근을 최소화하라
분류: 자바스크립트
JS를 통한 DOM 접근은 느립니다. 접근한 요소의 인덱스를 캐싱하고, 노드 변경은 최대한 오프라인에서 처리한 뒤 DOM 트리에 추가하세요. 레이아웃 문제를 JS로 해결하려 하지 마세요.
26. 스마트한 이벤트 핸들러를 사용하라
분류: 자바스크립트
모든 요소에 개별 이벤트 핸들러를 달지 말고 이벤트 위임(Event Delegation)을 활용하세요. 또한 onload 대신 DOMContentLoaded를 사용하여 이미지 다운로드 완료 전이라도 DOM이 준비되면 즉시 스크립트가 실행되게 하세요.
27. @import 대신 <link>를 선택하라
분류: CSS
IE에서 @import는 하단에 <link>를 둔 것과 같은 차단 효과를 발생시킬 수 있으므로 사용을 피하는 것이 좋습니다.
28. 필터(Filter) 사용을 피하라
분류: CSS
IE 전용 AlphaImageLoader 필터는 렌더링을 차단하고 메모리 소모를 키우는 등 여러 문제가 있습니다. 가급적 PNG8 이미지를 사용한 우아한 성능 저하를 선택하세요.
29. 이미지를 최적화하라
분류: 이미지
이미지 저장 후 업로드 전, 팔레트 크기 조정, PNG 변환, pngcrush나 jpegtran 같은 도구를 사용한 무손실 압축 등을 통해 파일 크기를 줄이세요.
30. CSS Sprite를 최적화하라
분류: 이미지
스프라이트 이미지 배치 시 가로 배치가 세로보다 용량이 작은 경우가 많으며, 유사 색상을 그룹화하여 색상 수를 줄이세요. 모바일 기기의 메모리 소모를 고려하여 불필요한 여백은 피하는 것이 좋습니다.
31. HTML에서 이미지 크기를 조절하지 마라
분류: 이미지
100x100 이미지가 필요하다면 500x500 이미지를 다운로드하여 HTML 속성으로 줄이지 말고, 처음부터 100x100 이미지를 사용하세요.
32. 작고 캐싱 가능한 favicon.ico를 사용하라
분류: 이미지
favicon.ico는 브라우저가 매번 자동 요청하므로 404가 발생하지 않게 하고, 1K 이하의 작은 크기와 긴 유효 기간 헤더를 설정하여 전송 부담을 줄이세요.
33. 모든 컴포넌트 크기를 25K 이하로 유지하라
분류: 모바일
아이폰 등 일부 모바일 기기에서 25K를 초과하는 컴포넌트(압축 전 크기 기준)를 캐싱하지 못하는 경우가 있으므로 이를 고려해야 합니다.
34. 컴포넌트를 하나의 복합 문서로 묶어라
분류: 모바일
이메일 첨부 파일처럼 여러 컴포넌트를 하나의 복합 문서로 묶어 요청 수를 줄일 수 있지만, 기기의 지원 여부를 먼저 확인해야 합니다.
35. 이미지 src 속성을 비워두지 마라
분류: 서버
이미지 src=""와 같이 비어 있는 경우, 브라우저는 해당 빈 문자열을 상대 경로로 인식하여 서버에 불필요한 추가 요청을 보낼 수 있습니다. 이는 서버 부하를 가중시키고 사용자 데이터를 오염시킬 위험이 있습니다.
아직 댓글이 없습니다