Rev. 2.73

analytics.gif

최근 자바스크립트의 사용량이 많아지면서 트래픽도 덩달아 증가하고 있다. CPU 연산 의존도가 높은 자바스크립트는 당장 필요치않은 라이브러리들까지 처리하려니 브라우저도 죽을 맛이다. 조금 더 효율적인 처리방법은 없을까?
근간 호스팅 업체에서 제공하는 트래픽 분석 프로그램을 모니터링해 보니 좌측화면과 같이 상위권을 휩쓸고 있다. 브라우저가 파일캐시를 한다지만 신규방문자가 70-80% 이상이면 이것이 대안이라고 보기 힘들다. 자바스크립트 파일을 패키드(packed)하여 단순히 크기를 줄이는 방법도 있지만 브라우저에 부담을 주는 것은 마찬가지이다.

예를 들어 보자. 이미지를 멋지게 표현해주는 라이트박스(Lightbox JS)를 설치했으나 방분객은 이미지를 조회하지 않고 떠났다. 방문객은 필요치않은 자바스크립트 파일들을 다운로드 한 결과를 가져왔다. 물론 서버단에서 이미지가 있는 경우만을 체크하여 라이브러리를 로드했다 하더라도 작동을 시키지 않은것 또한 낭비인것은 사실이다. 페이지에 꼭 필요한 자바스크립만 로드하고 나머지는 필요한 때 동적으로 로드하도록 구현하여 쾌적한 브라우징 환경을 제공하면서 트래픽 손실도 줄이는 일석이조의 효과를 누려보자.

우선 자바스크립트를 동적으로 불러올 함수가 필요하다. 일전에 소개했던 "인클루드 (자바스크립트 || 스타일시트) 파일"을 변형해서 사용했으며 내용은 아래와 같다.(예제에 사용된 코드는 Prototype.js 1.5.1_rc2 기반으로 작성됨)

자, 이제 준비는 끝났다. 예를 들어 Scriptaculous의 dragdrop.js(30.46kb)을 동적으로 호출하는 코드를 만들어보자.

//Include dragdrop.js on action
var Draggable = function(element, options){
	new Include('dragdrop.js', function(){
		new Draggable(element, options);
	}); 
};

'Draggable' 이라는 함수를 미리 선언했다. 이 함수는 dragdrop.js의 메인 클래스이름과 동일하다. 만약 어딘가에서 'Draggable' 클래스를 작동시키면 'dragdrop.js'파일이 로드되고 작동시킨 함수는 온컴플리트(onComplete) 이벤트에 의해 실행되며 위에서 미리 선언한 함수는 'dragdrop.js' 원래의 클래스로 오버라이드(override)되는 로직이다. 위 코드는 이곳에서 실제 사용되는 코드로 키워드 뷰어나 댓글수정 등(Draggable 이 적용된 곳)에 적용되어 있으니 직접 사용해보자. Firefox의 JSView 플러그-인을 설치하면 자바스크립트 및 스타일시트의 사용현황을 쉽게 확인 할 수 있다.

var FishEye = function(element){
    new Include('fisheye.js', function(){
        new FishEye(element);
    });
};
var CMotion = function(element){
    new Include('cmotion.js', function(){
        new CMotion(element);
    });
};
var Favicon = function(element){
    new Include('favicons.js', function(){
        new Favicon(element);
    });
};

위 코드는 어떤 역할을 할까? 그렇다. 해당 기능이 작동할 때에만 자바스크립트가 로드되고 오버라이드 된다. 'fisheye'는 어안메뉴이고, 'cmotion'은 블로그 상단의 썸네일 모션이며, 'favicons'는 댓글쓴이의 이름앞에 패비콘을 찍어주는 작은 단위의 라이브러리들이다. 이 함수들을 개별 파일로 분리하여 필요한 때에 필요한 파일을 동적으로 호출하는 것이다. 오버라이딩하는 기법을 사용하지 않고 아래처럼 단순히 로드해서 사용해도 무방하다.

if($$('pre code').length){
	new Include('syntax.js, syntax.css');
}

끝으로, 이 작업을 거친후 페이지당 약 50-60KB로 용량을 절약할 수 있었으며, 하루평균 최소 100MB이상의 트래픽 손실 및 비용 절감 효과가 있다는 결론이 나왔다. 더불어 브라우저가 로딩압박에서 조금은 벗어난 것을 체감할 수 있었다. 앞으로 30~50KB이상을 더 세부적, 체계적으로 분리할 예정이며, 마치 관례처럼 사용되고 있는 자바스크립트 사용법(All in header)에 조금씩 변화를 가져볼 생각이다.

※ 위 소스는 프로젝트 위키에서 다운로드 할 수 있습니다.

Comments

Got something to add? You can just leave a comment.

  • 나이스~~ 짝짝짝...

    reply edit

  • 좋네요!

    reply edit

  • 이벤트 이벤트

    점점 발전하는 모습이 보기 좋습니다. 아자~~

    reply edit

  • 감사합니다. ^^;

    reply edit

  • 좋은 소스 감사합니다. 덕분에 고민하나 줄었어요..
    오페라에서는
    else if(Prototype.Browser.Opera) {
    if(element.readyState == 'complete' || element.readyState == 'loaded') {
    options.onComplete();
    }
    }
    이렇게 추가해 주니 잘 작동 하네요.. 9.10에서 테스트 해 봤고 9.20에서는 테스트 못했습니다.

    reply edit

  • 테스트해 보니 오페라 9.20에서도 잘 돌아갑니다. 대단히 감사합니다.

    reply edit

  • FireJune 님의 \"자바스크립트 동적호출 구현하기\" 포스트를 보면서 대충 해결책을 찾은거 같네요. 깊은 내공없이 진행하는 코딩에는 항상 한계가 있나봅니다 :) 좋은정보 ..

  • ^^ 전 그냥 일일이 만들어 썼는데..ㅎㅎ 패키지화 시켜놓으셨네요 ㅎㅎ 이번 프로젝트때 한번 써봐야겠군요..ㅎㅎ 감사합니다.

    reply edit

  • 별말씀을요. 써주신다니 감사합니다. ^^; 피드백도 부탁드릴께요.

    reply edit

  • 편한사람 편한사람

    자바스크립트 동적호출 구현하기 어떻게 사용하는지 질문드리고 싶습니다.
    아래와 같이 하다가 막히네요...
    <SCRIPT src="prototype-1.6.0.2.js"></SCRIPT>
    <SCRIPT src="include.js"></SCRIPT>



    <SCRIPT LANGUAGE="JavaScript">
    <!--
    window.onload = function(){

    var Favicon = function(element, element2){
    new Include('input_allCheck.js', function(){
    new Input_allCheck(element, element2);
    });
    };

    Favicon(document.getElementById("inputClick"), "chk"); <----이렇게 하면 일단 객체는 생성이 되는지 모르겠습니다.
    그냥, 'input_allCheck.js'파일을 <SCRIPT src="'input_allCheck.js"></SCRIPT> 이와 같이 했을 때는 객체를 생성해서 하는 것은 잘 되는데, 위 소수와 같이 동적으로 어떻게 사용하는지를 모르겠습니다.
    바쁘신 와중에 이런 질문드려 죄송합니다.
    좋은 하루되세요.

    reply edit

  • var nput_allCheck = function(element, element2){
    new Include('input_allCheck.js', function(){
    new Input_allCheck(element, element2);
    });
    };

    답변이 늦어서 죄송합니다. 요즘 눈코 뜰세 없이 바빠서요... 위 처럼 클래스 네임과 동일한 변수에 Include를 할당하시면 됩니다.

    reply edit

  • 편한사람 편한사람

    답변주셔서 감사합니다.
    저번에 질문 드렸던 사람입니다.
    아래와 같이 생성했는데, Input_allCheck 에 할당되는 스크립트 코드는 아래와 같습니다.
    이게 잘 안되네요.. 어떻게 사용해야할 수 없을까요?

    Input_allCheck = function(ec_input, name_){
    this.ec_input = ec_input;
    this.name_ = name_;
    }

    Input_allCheck.prototype = {
    ExCheck: function(ec_input, name_) {
    this.name_ = name_;
    this.ec_input = ec_input;

    var El_length = document.getElementsByName(this.name_).length;
    if (El_length == null || isNaN(El_length)) return;

    for(var i=0;i < El_length ; i++){
    if(this.ec_input.checked)
    document.getElementsByName(this.name_)[i].checked = true;
    else
    document.getElementsByName(this.name_)[i].checked = false;
    }
    }
    }

    reply edit

  • js를 어떻게 동적으로 로딩할까 고민하고있었는데 이런 방법이 있었네요^^ 감사합니다~

    reply edit

  • 이버리 이버리

    이젠 받을수 없나요... 패쓰워드를 입력하게 되어있네요..ㅜㅜ

    reply edit

Your Reaction Time!

captcha

avatar