웹 브라우저상에서 페이지 이동이나 뒤로가기 앞으로가기 등 페이지 이력관리를 실제 페이지 이동없이 구현해주는 jQuery의 pushState와 Ajax를 합친 개념으로 탄생된 플러그인
웹사이트에서 사용자의 반응(링크클릭)등에 빠른 속도로 반응하는 것은 항상 웹개발자들의 꿈이다. 느려터진 웹사이트는 사용자를 짜증나게하고 이탈률을 증가시킨다. 가장 속도를 빠르게하는 것은 원격서버를 통하지 않고 로컬에서 다 해결하면 된다! 하지만 이것은 불가능한 일이다. 그래서 대안으로 나오는 것이, 전반적인 UI에 대해서는 로컬이 담당하고 필요한 데이터만 최소한으로 서버와 통신하는 방법이다. 이것이 SPA(Single Page Application) 방식에서 주로 쓰이는데 이러한 툴들로는 AngularJS나 ReactJS 등이 요즘 각광을 받고 있다.
SPA는 재빠른 반응을 구현할 때에는 최적이지만, 일종의 컨텐츠 서비스(커뮤니티나 블로그 등)은 상대적으로 SEO가 더 중요하며, 따라서 페이지별 독립된 트래픽이 발생할 수 있기에 거대한 하나의 번들 파일을 받게하는 것은 효과적이지 못하다.
pjax는 아주 단순하다. 특정 셀렉터(앵커태그)에 pjax를 바인딩하면, 해당 링크가 클릭되었을 때 타겟 주소에 대해서 서버에 요청을 하고, 바꿀 부문만 받아와서 바꿀 부분의 DOM만 갈아치우면서, pushState(HTML5)를 이용하여 브라우저의 주소도 변경을 해준다. 무언가 복잡해보이지만 필요한 부분만 받아와서 갈아치운다라는 원리는 ajax와 같다(실제로 내부적으로는 ajax를 쓴다). 이렇게 함으로써 위의 요구사항을 모두 만족시킬 수 있다.
아래는 실제 자주 쓰고 이곳 타일 블로그에도 사용한 스크립트이다. pjax에서 제공하는 이벤트와 메써드를 사용하여 기본 사용법을 약간 변형을 하였다. 서버를 하나도 건드리지 않고도 속도 최적화를 할 수 있는 옵션이다. 각각의 설명은 스크립트의 주석에 달아 놓았다.
<script>
$(document).on('click', 'a.pjax', function(e){ // pjax라는 클래스를 가진 앵커태그가 클릭되면,
$.pjax({
url: $(this).attr('href'), // 앵커태그가 이동할 주소 추출
fragment: '#posts-container', // 위 주소를 받아와서 추출할 DOM
container: '#posts-container' // 위에서 추출한 DOM 내용을 넣을 대상
});
return false;
});
// for google analytics
$(document).on('pjax:end', function() {
ga('set', 'location', window.location.href); // 현재 바뀐 주소를
ga('send', 'pageview'); // 보고한다
});
</script>
pjax를 안 썼을 때와 썼을 때를 이 블로그의 페이지 전환을 통해서 테스트를 해본 결과이다. 10번씩 각각 테스트하고 최소값과 최대값을 제외하고나서 평균을 내보았다. 대략 2.4배의 차이가 난다. 사실 네트워크 레이턴시가 있기 때문에 캐시하지 않는한 이 값이 극단적으로 차이가 나지는 않을것이지만, 중요한 것은 pjax로 하면 리프레시로 인해서 화면 깜빡임 자체가 없어지기 때문에 체감 속도는 훨씬 나게 된다.
:Redirection(ms) | pjax(ms): |
---|---|
1005 | 450 |
872 | 470 |
1243 | 402 |
위까지만 걸어줘도 페이지 전환 속도가 극적으로 향상되는 것을 느낄 수 있다. 하지만 이 경우에 헤더와 푸터 등 모든 마크업을 받아온 이후에 표시할 부문만 출력하기 때문에 완전히 최적화된 것은 아니다. 서버측에서 pjax로 들어온 것을 인식하여 헤더푸터를 제외하고 본문만 내려보는내 코드를 추가하면 된다. 만약 타겟에서 사이드바가 제외된다면, 사이드바에 들어가는 서버 쿼리도 제외시키면 더욱 향상이 될 것이다.
// ruby
def index
if request.headers['X-PJAX']
render :layout => false
end
end
pjax는 get 파라미터로 _pjax=true도 전송을 해주니, 이 값을 인식하여 헤더푸터를 날려주어도 된다. 이 포스팅에서 대해서 자세히 다루지 않는 것은 언어마다 템플릿 마크업을 어떻게 했느냐에 따라서 너무 천차만별이고, 사실 서버 자체에서도 어느정도 캐싱 등의 대안들을 마련했을 터이니, 여기 예시처럼 몽땅받아서 특정 DOM만 추출하는 방식을 쓰는 것도 생각보다 나쁘지는 않다.
본문쪽의 내용은 이제 동적으로 생성되는 컨텐츠 영역이 되었다(위의 경우 #posts-container). 따라서 기존 정적 페이지일 때에 걸어주었던 바인딩하는 방식을 최소한 저 컨테이너에 물리도록 교체를 해주어야 한다.
없다. 아주 HTML5의 기본스펙을 쓰기 때문에, 나중에 이 기술이 갑자기 사라질 일도 없다. 게다가 pushState를 쓸 수 없는 구닥다리 익스플로러 버전에서는 그냥 일반적인 페이지 이동이 발생하니, 호환성을 걱정할 필요도 없다(즉, 크롤러 입장에서는 그냥 일반 웹페이지처럼 작동). 이미 SEO가 되어있는-단독으로 접근 가능한 페이지-를 타겟팅하므로 SEO도 문제 없다. 굳이 따지자면 개발시 이 링크를 pjax로 작동시킬 것인가 안 시킬 것인가 고민 되는 정도가 있다.
(과거)
ajax 출현 전에는 iframe 기술을 이용해서 비슷한 처리를 하곤 했습니다. iframe 태그를 숨겨놓고, 서브밋을 날릴 때 iframe 태그에 서브밋을 날려서, 데이터를 가져온 다음에 현재의 페이지에 보여주는 방식을 이용하면 ajax 와 비슷하게, 페이지 이동없이 데이터를 가져와 뿌려줄 수 있었습니다. ajax 기술이 사용되기전에 한 때 많은 사이트에서 이용했던 방식중 하나
AJAX : 페이지의 새로고침없이 데이터를 가져와 화면에 뿌려주는 기능
누구나 ajax 방식의 처리를 구현해서 만들어 사용할 수 있지만, prototype.js 을 비롯한 jQuery 등의 등장으로 ajax 처리를 구현할 필요없이 쉽게 가져다 간단하게 API를 호출해서 사용할 수 있게 만들어 놓아, 더욱 더 많은 인기를 끌게 되었습니다. 그리고 ajax 는 웹을 빠르게, 그리고 멋지게 만들어 주었고요!
그런데 ajax 를 이용하면, 뒤로 가기 버튼을 이용할 수 없습니다. 게다가, HTML 소스를 열어봐도, ajax 에서 가져온 데이터가 어디에 있는지 찾을 길이 없습니다. 당연히, 검색사이트에서도 ajax 로 가져오는 데이터나 페이지들은 인덱싱을 해주지 못하므로, ajax 로 처리한 결과들은, 검색사이트에서 검색해도 검색결과를 얻을 수 없습니다.
그래서 이를 보완하기 위해 등장한 방식이 hashbang (hash:# 와 bang:! 의 합성) 기술인데, location.hash 를 이용해서, URL 의 #(hash) 뒤에 붙는 값을 이용해 ajax 처리를 합니다. 뒤로가기를 처리할 수는 있지만, 일종의 URL Hack 방식이어서, 정당성도 없고 논란의 중심에 있기도 한데, 검색인덱싱이 안되는 건 물론이고(구글에서는 검색을 할 수 있게 escape처리를 해놓음), JavaScript 기술에 의존하고 있기 때문에, JavaScript 오류 하나만으로도 사이트를 하나도 이용할 수 없게 되어버립니다. 즉 JavaScirpt 없이는 컨텐츠를 보여주지 못합니다. hashbang과 관련해서는 아웃사이더님 블로그에 잘 정리되어 있습니다.
마지막으로 이 모든 문제를 해결한, 비동기통신의 대안 pjax 를 소개합니다. 좀 거창하게 소개했는데 그렇게 거창할 건 없습니다. ^^; 우선 pjax 는 pushState + ajax 를 합쳐서 pjax 라 합니다. 여기서 pushState 는 HTML5 에서 추가된 메소드로 브라우저의 히스토리를 조작할 수 있고, 뒤로가기/앞으로가기 버튼을 이용할 수 있습니다. (현재는 github 과 facebook 등에서 쓰이고 있는 걸로 알고 있습니다.)
pjax는 pushState 를 이용한 ajax 처리방식으로 jQuery 라이브러리로 제공되고 있고, github 의 창립자이자, CEO 인 defunkt (Chris Wanstrath) 가 개발했습니다. pushState 를 지원하는 브라우저에서는 pushState 를 사용해서 동작하고, pushState 비지원 브라우저(IE9 이하) 에서는 지원하지 않는 대로 일반적인 페이지 이동형태로 처리가 이루어지기 때문에 URL은 동일하게 전환하게 됩니다.
위의 링크에 몇가지 방식으로 나와 있는데 간단하게는 링크를 잡고, 그 링크를 어느 컨테이너로 처리할 지 잡아서, pjax 처리를 해주면 됩니다.
가령, js-pjax 클래스를 가진 a 링크만을 pjax 처리한다면 아래 코드와 같습니다.
<a href=’/explore’ class=’js-pjax’>Explore</a>
$(‘.js-pjax’).pjax(‘#main’)
샘플을 보면 쉽게 이해할 수 있습니다. pjax 체크박스를 체크하고 링크를 누르면, 시간이 변하지 않습니다. 즉 해당영역만 링크를 다시 가져오는 것을 볼 수 있습니다. pjax 체크박스를 풀고 링크를 누르면 페이지가 리로드되는 일반적인 방식으로 페이지를 로드합니다. (내친김에 IE9 이하 에서도 pjax 처리는 하지 않고, 일반적인 방식으로 페이지를 로드합니다)
pjax 샘플 http://pjax.heroku.com/
흥미로운 점이 많아서, 혹시 단점은 없나 찾아봤는데,
HTML5 라 IE9 이하 하위버전에서 지원하지 않는 점만 빼면,
앞으로의 비동기 통신기술의 대안이 아닐까 싶습니다.
출처
https://tyle.io/blog/pjax%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EA%B7%B9%EC%A0%81%EC%9D%B8-%EC%9B%B9%ED%8E%98%EC%9D%B4%EC%A7%80-%EC%86%8D%EB%8F%84-%ED%96%A5%EC%83%81?loc=ko
https://github.com/defunkt/jquery-pjax
https://xetown.com/topics/6603
http://blog.outsider.ne.kr/698
https://rkjun.wordpress.com/2012/05/29/ajax-%EC%99%80-hashbang-%EA%B7%B8%EB%A6%AC%EA%B3%A0-pjax/