최근의 글 "겸손한 Script를 통한 게으른 로딩 기능"은 HEAD 태그에 script 엘리먼트를 추가함으로써 JavaScript 스크립트 파일을 게으르게 로딩하는 법을 논의했습니다.

제대로 동작하기는 하지만, 이미 읽은 스크립트를 다시 읽는 것을 방지하기위해 읽힌 스크립트를 추적하는 것도 고려해야하고, 함수를 호출하기 전에 의존성있는 스크립트가 다 읽혔는지 보증해줄 방법으로 콜백을 지원하는 것도 중요합니다.
[code:js]
/**
*  Script lazy loader 0.5
*  Copyright (c) 2008 Bob Matsuoka
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) any later version.
*/
 
var LazyLoader = {}; //namespace
LazyLoader.timer = {};  // contains timers for scripts
LazyLoader.scripts = [];  // contains called script references
LazyLoader.load = function(url, callback) {
        // handle object or path
        var classname = null;
        var properties = null;
        try {
                // make sure we only load once
                if ($A(LazyLoader.scripts).indexOf(url) == -1) {
                        // note that we loaded already
                        LazyLoader.scripts.push(url);
                        var script = document.createElement("script");
                        script.src = url;
                        script.type = "text/javascript";
                        $$("head")[0].appendChild(script);  // add script tag to head element
                      
                        // was a callback requested
                        if (callback) {   
                                // test for onreadystatechange to trigger callback
                                script.onreadystatechange = function () {
                                        if (script.readyState == 'loaded' || script.readyState == 'complete') {
                                                callback();
                                        }
                                }                           
                                // test for onload to trigger callback
                                script.onload = function () {
                                        callback();
                                        return;
                                }
                                // safari doesn't support either onload or readystate, create a timer
                                // only way to do this in safari
                                if ((Prototype.Browser.WebKit && !navigator.userAgent.match(/Version\/3/)) || Prototype.Browser.Opera) { // sniff
                                        LazyLoader.timer[url] = setInterval(function() {
                                                if (/loaded|complete/.test(document.readyState)) {
                                                        clearInterval(LazyLoader.timer[url]);
                                                        callback(); // call the callback handler
                                                }
                                        }, 10);
                                }
                        }
                } else {
                        if (callback) { callback(); }
                }
        } catch (e) {
                alert(e);
        }
}
전체 소스와 예제 프로젝트 다운로드

읽힌 스크립트 추적
게으른 로더는 보통 실행할 특정 스크립트를 위해 필요한 스크립트를 지정하는 "require" 형태의 함수를 사용합니다. 라이브러리 스크립트들이 종종 한 개 이상의 script에 의해 호출되기 때문에, 저는 불필요한 리로딩을 방지하기 위해 페이지에서 어떤 스크립트가 이미 읽혔는지 추적하는 기능을 제 게으른 로더에 넣는 것이 중요하다고 생각했습니다.

이 예제에서, 저는 LazyLoader.script 배열을 만들었습니다. 각각의 스크립트가 호출되면서 이 스크립트의 src는 이미 읽힌 스크립트의 배열에 있는지 테스트되고, 만약 존재한다면 리로드하지 않고 콜백을 실행합니다. 이는 어떤 스크립트라도 필요할 때마다 손실없이 호출할 수 있도록 해줍니다.

콜백 지원
더 중요한 추가사항은 콜백의 지원입니다. 제 경험상, 콜백이 로딩 프로세스에 묶여있지 않는 한 사용할 수 있는 상태에 있는 스크립트를 보장해주는 것은 이만한 게 없습니다. 안타깝게도 대부분의 브라우저들은 onload 이벤트를 조금씩 다른 방식으로 다룹니다. 제가 제공하는 예제는 Firefox, Safari, IE에서 동작합니다.

콜백 지원의 가장 기본적인 로직은 클로져가 게으른 로더에 전달되는 것입니다. 그러면 함수는 script가 로딩되면서 발생하는 이벤트에 묶입니다. FF와 Safari 3는 "onload" 이벤트를 지원합니다. IE는 onreadystatechange 이벤트를 제공하며, state가 'loaded'나 'complete' 상태인지 체크하는 부분이 더 필요합니다('loaded', 'complete' 는 캐시 여부에 따름).

Safari2와 Opera에서의 콜백 지원은 "onload"나 "onreadystatechange"와 같은 script  이벤트를 지원하지 않기때문에 요령이 필요합니다. 이들 브라우저에는, document.readyState가 "loaded"인지 "complete"인지 체크할 간격이 매우 짧은 스크립트가 필요합니다. 준비가 되고 나면, 반복 스크립트를 중단하고 콜백을 실행합니다(저는 각각의 script를 따로 체크했습니다만, 우리가 체크하는 것이 개별  script가 아니라 document객체라 개별 체크가 꼭 필요한 것인지는 잘 모르겠습니다).

로더 호출
로더 호출은 간단합니다. 이 구현물은 네임스페이스를 사용한 정적 함수입니다. 콜백이 없는 예제를 보시죠:
[code:js]
LazyLoader.load('js/myscript1.js');
아래는 콜백이 있는 예제입니다.
[code:js]
LazyLoader.load('js/myscript2.js', function(){
    var myobj = new MyObject('myobj');
});
두번째 예제에서, MyObject의 "myobj" 인스턴스는 js/myscript.2js가 로딩된 뒤에 생성됩니다. 콜백 함수를 이용해서 연쇄 로더를 만들 수도 있습니다.

결론
저는 근 1년간 이 기술을 사용해오면서 좋을 결과를 얻었습니다. 우리는 같은 "레이아웃" 을 공유하는 특정 페이지들에서만 필요한 객체와 함수들의 매우 거대한 라이브러리를 사용합니다. 이 기술은 우리에게 적합하고 분명한 스크립트만 호출하도록 해줍니다(HEAD 태그에서. 페이지의 body에 script 참조를 포함하는 것과 대조적입니다). 우리는 이 함수를 스크립트의 의존성이 명확한 "require" 함수를 동시에 호출할 때도 사용할 수 있습니다.

스크립트 로더는 또한 폼 기반 스크립트를 동시에 로딩할 때에도 매우 잘 동작합니다. 서버 사이드 변수에서 만큼이나 스크립트 객체를 참조하고 HTML 폼을 바인딩하는데 이 기술을 사용합니다. 여기에 대해서는 나중에 다루도록 하겠습니다.

from A Technique For Lazy Script Loading
Posted by 행복한고니 트랙백 0 : 댓글 0

댓글을 달아 주세요