Rev. 2.73

굵직한 자바스크립트 관련 웹 프로젝트들을 진행하다 보면 개발자간 협업에서 부디치는 문제가 상당수 있습니다. 뜻하지 않게 네임스페이스를 비효율적으로 사용하거나 이벤트가 무작위로 생성되기도 하고 심지어 중복된 결과를 낳는 함수를 각자 개발하는 사례도 있습니다. 특히, window객체에 할당하는 이벤트 처리는 전역에 걸쳐 발동하게 되기 때문에 코드 자체를 작업자간에 공유하여 작업하거나 window.onload와 같은 이벤트를 중복해서 할당해 버리는 경우도 많습니다. 이 문제를 조금 더 효율적으로 처리할 방법을 강구하다가 아래와 같은 이벤트의 재사용 방법을 모색하게 되었습니다.

/**
 * Dynamic event observation
 *
 * @author firejune <to [at] firejune [dot] com>
 * 
 * @usage : 
 *   - Event.addObserve['load'].initializeTooltip = new Tooltip;
 *   - Event.addObserve['resize'].accordionResize = function() { 
 *       Accordion.resize(); 
 *     };
 * 
 * @requires 
 *   - prototype.js <prototypejs.org>
 * 
 */

Event.addObserve = {
  load : {},
  scroll: {},
  resize: {}
};

// Align global event-oservers
for (var evt in Event.addObserve) {
  var eventObj = Event.addObserve[evt];
  var attachFunc = Prototype.emptyFunction;

  if (!eventObj) continue;

  // Call the functions
  var callFunctions = function(bind, obj) {
    var report = [];
    for (var func in obj) {
      if (func && typeof obj[func] == 'function') {
        obj[func](bind);
        report.push(func);
      } else {
        //debug(obj[func], 'is not a function');
      } 
    }
    //debug('called functions: ' + report);
  };

  if (evt == 'load') {
    attachFunc = callFunctions.bindAsEventListener(this, eventObj);
  } else {

    // Better performance for IE
    attachFunc = function() {
      if (typeof Event.oserveTimeOut == "number") {
        window.clearTimeout(Event.oserveTimeOut);
        delete Event.oserveTimeOut;
      }
      Event.oserveTimeOut = setTimeout(function(){
        callFunctions(this, eventObj);
      }.bind(this), 100);
    }.bindAsEventListener(this);
  }

  // Observing Events
  Event.observe(window, evt, attachFunc, false);
}

이로써 window객체로 할당되는 이벤트를 재사용하여 함수를 동적으로 관리할 수게 되었습니다. 그리고 윈도 리사이즈와 스크롤 이벤트에는 성능향상을 위해 100 밀리세컨즈 뒤에 실행되도록 setTimeout이 적용되어 있습니다. 유저의 무리한 컨트롤에 대응하고 쓸대없는 계산을 줄이기 위해서 입니다. 위 코드를 적절한 곳에서 한번만 실행되게 하면 아래처럼 필요한 때에 추가/대체/무력화 할 수 있습니다. 단, 라이브러리(Open source, Open API)와 같은 비의존성 겸손한(Unobtrusive) 자바스크립트 프로그래밍과는 거리가 멀기 때문에 항상 유용한 것은 아니라는 점 참고하시기 바랍니다.

// A개발자의 Tooltip 클래스가 초기화 되기위한 이벤트 핸들러
 // 단, 온로드 이벤트가 발생하기 전에 선언해야 한다. 
 Event.addObserve['load'].initializeTooltip = Tooltip = new Tooltip;

 // B개발자의 Accordion 클래스가 초기화 되기위한 추가 이벤트 핸들러
 Event.addObserve['load'].initializeAccordion = Accordion = new Accordion;

 // B개발자의 Accordion 리사이즈 이벤트 핸들러
 Event.addObserve['resize'].accordionResize = Accordion.resize; 

 // A개발자의 Tooltip 클래스에 필요한 문서크기 재계산 추가 이벤트 핸들러
 Event.addObserve['resize'].tooltipResize = function() { 
   var element = $('element1') || $('element2');
   Tooltip.setDocumentPositions(element); 
 };

 // B개발자가 추가했던 Accordion 리사이즈 이벤트 핸들러 무력화
 Event.addObserve['resize'].accordionResize = null; 

Comments

John-David Dalton씨는 오래 전부터 PrototypeScriptaculous를 압축하여 페이지 로딩속도를 향상시키는 방법을 소개하고 다양한 형태로 압축된 파일들을 구글 그룹스를 통해 배포하고 있습니다. 그리고 지난 20일에는 Prototype 1.6과 Scriptaculous 1.8버전이 추가된 업데이트(protopacked_v2.17)를 공개했습니다. prototype.js(1.6) 파일용량은 121kb입니다. 이 것을 압축하여 46.1kb로 줄이고 다시금 Gzip으로 압축 전송하면 고작 20.6kb입니다. 자바스크립트의 용량을 실시간으로 줄이는 Minify를 사용했을 때 90.5kb로 줄어드는 것에 비하면 상당량 줄어든 것임을 알 수 있습니다.(Minify된 파일을 Gzip으로 압축 전송하면 22.6kb입니다.) 12월 20일짜 Packed버전에는 "Protoculous"라는 이름을 가진 새로운 형태의 압축파일이 있으며, 이 것은 Prototype과 Scriptaculous가 합쳐진 것이라고 합니다.
.

<!-- Good: -->
<script type="text/javascript" src="prototype.js"></script>

<!-- Good: -->
<script type="text/javascript" src="gz.php?src=prototype"></script>

<!-- Good: -->
<script type="text/javascript" src="protoculous.js?load=addon"></script>

<!-- Bad: -->
<script type="text/javascript" src="prototype.gz"></script>

참고로, 자바스크립트 파일을 압축하는 도구로는 Dojo ShrinkSafeDean Edwards씨의 Packer가 사용되었습니다.

Comments

buddy.gif

AjaxIM은 누구나 웹상에 설치해서 사용할 수 있는 Ajax기반 인스턴트 메신저(IM)입니다. PrototypeScriptaculous, Prototype Window, SoundManager2 등의 자바스크립트 라이브러리가 사용되고 있으며, 백-엔드 플랫폼은 PHP로 작성되었습니다. 친구 목록을 그룹으로 관리할 수 있는 목록창과 이모티콘 삽입, 텍스트 스타일을 커스토마이즈하여 대화할 수 있는 대화창으로 구성되어 있습니다. 다국어 설정, 테마 변경, 사용자 차단, 관리자 패널 등의 기능을 제공합니다. 실험을 위해 저도 설치해 보았는데요. im.firejune.com에서 테스트해 볼 수 있으며, 저와 대화 하시려면 'firejune'을 초대하시면 됩니다. 어딘가에 응용할 곳이 있을 듯 한데요.

Comments