빠른 HTML5 웹앱을 위한 최고의 사례들

HTML5 Rocks

이 기사는 성능 이야기의 일부분만을 다룹니다. 해당 링크를 확인하시면 html5rocks.com/features/performance 성능 향상의 전체적인 윤곽을 확인하실 수 있습니다.

소개

HTML5는 네이티브 브라우저에서 여태까지 Javascript 라이브러리 구현한 기술과 컴포넌트들을 지원하는데 초점을 맞추고 있습니다. 이러한 기능들을 이용하면 사용자들에게 더 빠른 사용자경험을 제공할 수 있습니다. 이번 튜토리얼에서는 야후의 Exceptional Performance site 나 구글의 Google's Page Speed docs 그리고 Let's make the web faster 사이트에서 다룬 성능 연구를 다루지 않습니다. 대신에 HTML5와 CSS3를 이용하여 어떻게 앱을 더 반응형으로 만들 수 있는데 집중하겠습니다.

Tip 1: 웹 스토리지에 쿠키 저장하기

쿠키는 사용자의 특정 데이터를 추적하기 위해 오랫동안 사용해왔지만, 심각한 단점이 있습니다. 가장 큰 단점은 모든 쿠키 데이터가 각 HTTP 요청 헤더에 다 추가되는 점입니다. 이렇게 되면 응답시간에 상당한 영향을 줄 수 있고, 특히 XHRs 중간에 더 그렇습니다. 그렇기 때문에 쿠키 크기를 줄이는 것이 베스트 프랙티스에 해당됩니다. HTML5 에서는 sessionStoragelocalStorage를 이용하여 쿠키를 저장할 수 있습니다.

이 두 스토리지 객체는 클라이언트 사이드에서 세션의 길이에 맞추거나 무한대로 데이터를 지속저장할 수 있습니다. 이 데이터는 모든 HTTP 요청을 통해 서버에 전송되지 않습니다. 아래 API는 실패시에 쿠키를 사용하도록 되어 있습니다.

// if localStorage is present, use that
if (('localStorage' in window) && window.localStorage !== null) {

  // easy object property API
  localStorage.wishlist = '["Unicorn","Narwhal","Deathbear"]';

} else {

  // without sessionStorage we'll have to use a far-future cookie
  //   with document.cookie's awkward API :(
  var date = new Date();
  date.setTime(date.getTime()+(365*24*60*60*1000));
  var expires = date.toGMTString();
  var cookiestr = 'wishlist=["Unicorn","Narwhal","Deathbear"];'+
                  ' expires='+expires+'; path=/';
  document.cookie = cookiestr;
}

Tip 2: Javascript 애니메이션 대신에 CSS Transition 사용하기

CSS Transitions 은 두 상태 간의 매력적인 가시화 전환(Visual Transition)을 보여줍니다. 대부분 스타일 속성은 text-shadow, position, background, color 등의 조작으로 전환이 가능합니다. :hover 상태나 HTML5 forms 에서 :invalid and :valid (example with form validation states) 같은 pseudo-selector 상태로의 전환도 가능합니다. 하지만 class에 요소로 추가하는 것이 더 강력합니다.

div.box {
  left: 40px;
  -webkit-transition: all 0.3s ease-out;
     -moz-transition: all 0.3s ease-out;
       -o-transition: all 0.3s ease-out;
          transition: all 0.3s ease-out;
}
div.box.totheleft { left: 0px; }
div.box.totheright { left: 80px; }
    

tothelefttotheright 클래스를 추가해서 박스를 움직일 수 있습니다. 이 코드와 Javascript Animation 코드 양을 비교해보세요. CSS 애니메이션은 브라우저에 보내는 바이트의 숫자 양이 확실하게 더 적습니다. 추가적으로, GPU 변속 레벨도 CSS를 이용할 때 훨씬 부드럽습니다.

Tip 3: 서버 왕복보다는 클라이언트 사이드 데이터베이스 사용하기

Web SQL DatabaseIndexedDB 는 클라이언트 사이드의 데이터베이스입니다. form 제출이나 XMLHttpRequest 통해서 서버로 데이터를 전송하는 흔한 패턴 대신에, 클라이언트 사이트 데이터베이스를 활용할 수 있습니다. Performance 엔지니어들은 성능 향상을 위해서 HTTP 요청수를 줄이는데 집중하기 때문에, 이 디비들을 저장소로 활용하면 XHR을 통한 요청이나 form을 통한 서버 요청 수를 많이 줄일 수 있습니다. localStoragesessionStorage 는 form 제출 과정을 캡쳐하는 등의 경우에서 사용됩니다. 그리고 이건 확실히 클라이언트 사이드 데이터베이스 API보다 빠릅니다.

예를 들면, 만약 데이터 그리드 컴포넌트를 사용거나 몇백개의 메시지가 있는 인박스를 이용한다고 하면, 데이터를 로컬 디비를 이용해서 저장하면 사용자가 검색, 필터, 정렬할 때 HTTP 왕복 요청을 많이 줄일 수 있습니다. 친구 목록이나 텍스트 자동완성 경우에도 타이핑을 할 때마다 더 빠른 사용자 경험을 제공하게 됩니다. 더 자세한 가이드는 Web SQL Database tutorial에서 확인하세요.

Tip 4: JavaScript 개선으로 얻게 되는 상당한 성능 이점들

JavaScript 1.6에 많은 메서드들이 Array 프로토타이프에 추가 되었습니다. IE를 제외한 대부분의 브라우저에서 사용이 가능합니다. 아래 예제를 봅시다:
// 모든 값에 10을 곱한 값을 가진 배열을 얻습니다.
[5, 6, 7, 8, 900].map(function(value) { return value * 10; });
// [50, 60, 70, 80, 9000]

// 스펙을 볼 수 있는 링크를 만들고 각 값을 링크에 추가합니다.
['html5', 'css3', 'webgl'].forEach(function(value) {
  var linksList = document.querySelector('#links');
  var newLink = value.link('http://google.com/search?btnI=1&q=' + value + ' spec');
  linksList.innerHTML +=  newLink;
});


// 상수 값이 2 이하인 값에 대해 새로운 배열을 만들어 반환합니다.
[3.14, 2.718, 1.618].filter(function(number) {
  return number < 2;
});
// [1.618]


// 이 추가 API 들을 다른 콜렉션에 nodeLists 처럼 이용할 수 있습니다.
[].forEach.call(document.querySelectorAll('section[data-bucket]'), function(elem, i) {
  localStorage['bucket' + i] = elem.getAttribute('data-bucket');
});
    

대부분의 경우에 네이티브 메서드를 활용하면
for (var i = 0, len = arr.length; i < len; i++).

같은 전형적인 반복문보다 속도가 훨씬 빠릅니다.

JSON.parse()을 통한 네이티브 JSON 파싱은 여태까지 우리가 사용해왔던 json2.js 파일을 교체했습니다. 네이티브 JSON은 외장 스크립트를 사용하는 것보다 훨씬 빠르고 안정적입니다. 그리고 이미 IE8, Opera 10.50, Firefox 3.5, Safari 4.0.3과 크롬에서 사용이 가능합니다.

네이티브 String.trim 은 동일한 효과의 긴 JS 보다 빠를 뿐만아니라 잠재적으로 더 올바른 좋은 예로 볼 수 있습니다. 이러한 Javascript들의 추가는 기술적으로 말해서 HTML5라고 볼 순 없습니다. 하지만 최근에 추가된 활용 가능한 기술들입니다.

Tip 5: 오프라인 앱뿐만 아니라 라이브 사이트들에도 캐쉬 매니페스트 사용하기

2년 전에 Wordpress는 Wordpress Turbo 기능을 추가하기 위해서 Google Gears 를 사용하였습니다. 이 기능은 관리자 영역에서 사용되는 많은 리소스들을 캐쉬하였고, 리소스들에 대한 파일 접근 속도를 높였습니다. 이러한 동작을 HTML5's applicationCache와 cache.manifest로 구현할 수 있습니다.

앱 캐쉬는 Expires 헤더를 세팅시 약간의 이점이 있습니다. 왜냐면 캐쉬가 가능한 정적인 리소스를 선언하는 파일을 만들 수 있기 때문입니다. 브라우저는 이를 통해 상당하게 최적화를 할 수 있고, 심지어 당신이 사용하기 전에 미리 캐쉬가 가능합니다.

당신 사이트의 기본적인 구조가 템플릿 이라고 합시다. 이 사이트의 데이터는 바뀔 수 있지만 HTML는 일반적으로 변하지 않습니다. 앱 캐쉬를 이용했을 때, HTML을 변하지 않는 템플릿으로 보고 cache.manifest를 이용하여 마크업을 캐쉬할 수 있습니다. 그리고나서 내용 업데이트를 위해 JSON을 사용할 수 있습니다. 이 모델은 iPhone이나 Android 같은 네이티브 news 앱과 성격이 비슷합니다.

자세한 내용은 application cache tutorial에서 확인하세요.

Tip 6: Visual Experience 향상을 위해 하드웨어 가속 활성화하기

앞서 나가는 브라우저에서는 GPU-레벨 가속을 이용하여 눈에 보이는 동작을 훨씬 더 부드럽게 할 수 있습니다. 하드웨어 가속은 Firefox Minefield and IE9 에서 지원하고, Safari에서도 하드웨어 레벨의 가속을 5 버전에 추가하였습니다 (모바일 사파리는 더 빨리 지원되었습니다). 크롬은 3D transforms 과 하드웨어 가속을 Windows에 얼마 전에 추가 하였고, 다른 2개 플랫폼은 곧 추가될 것입니다.

GPU 가속은 제약적으로 특정 몇몇 조건에서만 실행되지만, 3D transforms 와 animated opacity 가 실행할 수 있는 가장 흔한 방법입니다. 조금은 hacky 하지만 실행할 수 있는 방법은 다음과 같습니다:

  .hwaccel {  -webkit-transform: translateZ(0); }

이 방법이 보장되지는 않습니다 :)

활성화와 지원이 가능한 하드웨어 가속과 GPU 구성으로 전환, 회전, 크기 변환, 투명도 변환 등의 애니메이션이 더 부드러워 질 것입니다. GPU에서 직접 처리하게 되면 이점이 생기고 layer contents 를 다시 그릴 필요가 없습니다. 그러나, 페이지의 레이아웃에 영향을 미치는 속성은 여전히 상대적으로 느릴 것입니다.

Tip 7: CPU를 많이 소모하는 동작은 Web Workers로 처리하기

웹 워커는 2가지의 큰 이점이 있습니다. 1) 빠릅니다. 2) 태스크를 처리하는 동안 브라우저는 반응할 수 있습니다. HTML5 Slide Deck 에서 어떻게 워커가 동작하는지 확인해보세요.

웹 어커를 사용할 수 있는 몇가지 상황은 아래와 같습니다.

  • 긴 문서의 텍스트 포맷 설정
  • 구문 하이라이팅
  • 이미지 처리
  • 이미지 합성
  • 큰 배열 처리

Tip 8: HTML5 폼 속성과 입력 타입

HTML5 다음과 같이 새로운 입력 타입을 도입하였습니다. text, password, and file to include search, tel, url, email, datetime, date, month, week, time, datetime-local, number, range and color. 브라우저는 다양하게 이 기능들을 지원하고 Opera 이 시점에서 기능을 구현하고 있습니다. 브라우저가 네이티브 지원을 하는지 확인할 수 있고, datepicker나 color picker 같은 UI 를 지원하는지도 확인이 가능합니다. 만약 지원이 안되면, JS 위젯을 이용하여 이러한 기능들을 구현할 수 있습니다.

이 타입들과 더불어서, 몇가지 유용한 기능들이 일반 input field에 추가 되었습니다. placeholder 는 클릭시에 default text 를 비울 수 있는 기능을, autofocus 는 페이지 로딩시에 해당 영역에 바로 초점이 가게 합니다. Input Validation은 HTML5을 더 유용하게 합니다. required 속성은 해당 영역에 값이 없으면 브라우저가 폼 제출을 하지 못하게 합니다. pattern 속성은 입력에 대한 커스텀 정규표현식을 지정하여 형식에 어긋나는 값을 제출하지 못하게 합니다. 이렇게 미리 정의된 속성들은 소스 가독성을 올릴 뿐만 아니라 Javascript 의 필요성을 상당하게 줄였습니다. 만약 이 기능들이 네이티브에서 지원이 되지 않으면 feature detection 을 이용하여 실패 경우를 대비할 수 있습니다.

이러한 네이티브 위젯을 활용하면 무거운 Javascript나 CSS를 보낼 필요가 없고, 페이지 로딩 속도가 빨라지고 위젯 반응성이 향상됩니다. 이 input 향상을 체험하고 싶다면 HTML5 Slide deck 을 확인해보세요.

Tip 9: 무거운 이미지 스프라이트 요청 대신에 CSS3 효과 사용하기

시각적인 디자인을 정확하게 표현하기 위해 사용하는 이미지 대신 사용할 수 있는 CSS3 스타일들이 있습니다. 2k 이미지를 100 바이트의 CSS로 바꾸는 건 엄청난 이득입니다. 또한 HTTP 요청 하나를 줄이는 효과도 생깁니다. 이런 특성과 관련해서 알아둬야 할 몇가지 속성은:

  • 선형과 방사식의 그래디언트 (gradients)
  • 둥근 코너의 가장자리 길이 (Border-radius)
  • drop shadow와 glow의 Box-shadow
  • RGBA for alpha opacity
  • 로테이션 변환
  • CSS masks

예를 들어, 그레디언트를 이용해서 polished buttons 을 생성하거나 다른 효과 복제를 sans-images로 할 수 있습니다. 브라우저는 이들 대부분을 전적으로 지원하고 있고, Modernizr 같은 라이브러리를 이용하여 실패한 경우 이미지를 사용하기 위해 기능을 지원하지 않는 브라우저들을 확인할 수 있습니다.

Tip 10: XHR보다 적은 대역폭을 이용한 WebSockets의 빠른 전송

WebSocketsComet의 인기 성장세에 힘입어 제작 되었습니다. 그리고 이제 XHR 모델을 이용한 Comet 보다 웹 소켓을 사용할 때 이점이 있습니다.

웹 소켓은 매우 가벼운 프레이밍(light framing) 입니다. 그래서 웹소켓을 사용하는 대역폭이 종종 XHR 보다 가볍습니다. Some reports 에서는 전송시에 바이트가 35%가 감소된다고 합니다. 추가적으로, 많은 양의 메시지를 전송할 때 성능의 차이가 명확히 드러납니다; in this test 에서 보면, XHR이 웹 소켓보다 3500% 긴 시간의 aggregate time 으로 레코딩 되었습니다. 마지막으로, Ericcson Labs considered the performance of WebSockets 에서는 XHR의 HTTP ping 시간이 더 큰 처리 요구사항 때문에 웹 소켓보다 3~5배 정도 더 크다고 나와있습니다. 실시간 어플리케이션에는 웹 소켓 프로토콜이 확실히 더 적합하다라고 결론이 났습니다.

추가적인 리소스들

성능 추천과 측정은 Firefox의 Page SpeedYSlow를 이용합니다. 추가적으로 Speed Tracer for ChromeDynaTrace Ajax for IE 는 분석 로그를 더 자세한 레벨에서 제공합니다.

guide to Chrome's Developer Tools 의 리소스 탭에서도 유용한 기능들을 제공하고 곧 new Audits panel 가 추가될 것입니다.

Comments

0