javascript

자바 스크립트 동적 로딩 JavaScript,Ajax

jeeyong 2009. 7. 28. 18:45

Ajax가 제공하는 편리한 UI 덕에, 점점 더 많은 기능들에 Ajax가 적용되고 있는 추세이다. (예를 들어, 다음 카페의 관리 메뉴에서 메뉴 관리나 회원 관리 등은 Ajax에 기반해서 구현되었다.) 이에 따라 자바 스크립트 코드의 규모도 커지고 하나의 페이지를 구현하는 데 필요한 자바 스크립트 모듈 개수도 증가하고 있다.

문제는 로딩해야 할 자바 스크립트 파일 개수가 점차 늘어나면서 웹 페이지가 로딩될 때 함께 로딩되는 파일 개수 및 크기가 증가한다는 점이다. 자바 스크립트 파일을 다운로드 하는 시간만큼 웹 브라우저가 초기 페이지를 실행하는 시간은 지연되고, 또한 전혀 사용되지 않을 수도 있는 자바 스크립트 코드인데도 불필요하게 모든 자바 스크립트 파일을 로딩하는 문제도 있다.

jsDynamicLoader 모듈

그래서 필요할 때 자바 스크립트 파일을 동적으로 로딩해서 관련 모듈을 실행하는 방법을 찾아봤는데, 코드를 정리해보면 다음과 같다.

코드: jsDynamicLoader.js

function loadJavascript(url, callback, charset) {
    var head= document.getElementsByTagName('head')[0];
    var script= document.createElement('script');
    script.type= 'text/javascript';
    if (charset != null) {
        script.charset = "euc-kr";
    }
    var loaded = false;
    script.onreadystatechange= function () {
        if (this.readyState == 'loaded' || this.readyState == 'complete') {
            if (loaded) {
                return;
            }
            loaded = true;
            callback();
        }
    }
    script.onload = function () {
        callback();
    }
    script.src = url;
    head.appendChild(script);
}

위 코드의 실행 순서는 다음과 같다.

  1. <script> 노드를 생성하고, type 속성과 charset 속성을 설정한다.
  2. 웹 브라우저가 스크립트 파일의 로딩을 완료했을 때, callback 함수를 호출하도록 설정한다.
    1. IE인 경우, script.onreadystatechange를 이용해서 로딩 완료 여부를 확인한다.
    2. Firefox, Chrome 등, script.onload를 이용해서 로딩 완료 여부를 확인한다.
  3. script.src 속성에 로딩할 자바 스크립트 파일을 설정한다.
  4. <script> 노드를 <head> 노드에 자식으로 추가한다.

IE를 처리하기 위해서 onreadystatechange 함수를 보면, readyState가 'loaded'인 경우와 'complete'인 경우를 모두 처리해주고 있는데, 그 이유는 IE가 로딩할 스크립트 파일을 서버로부터 변경 여부를 확인하지 않고 캐시로부터 읽어오는 지의 여부에 따라서 readyState의 값이 다르기 때문이다.

  • IE가 서버에서 파일을 읽어오는 경우 readyState의 값은 'loaded'가 되고, 'complete'는 되지 않는다.
  • IE가 캐시에서 바로 파일을 읽어올 경우 readyState의 값은 'loaded'가 되지 않고, 'complete'가 된다.

이런 이유로 위 코드에서는 readyState가 'loaded'인 경우와 'complete'인 경우를 알맞게 처리할 수 있도록 하였다.

모듈 사용법

jsDynamicLoader.js를 사용하는 방법은 아래와 같이 간단하다.

코드: loadingtest2.html

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr" />
<meta>
<title>Test</title>
<script type="text/javascript" src="jsDynamicLoader.js"></script>
<script type="text/javascript">
function loadingModule1AndRun() {
    loadJavascript("module1.js", runModule1, "euc-kr");
}

function runModule1() {
    sayHello();
}
</script>
</head>
<body>
<input type="button" value="sayHello() 실행" onclick="sayHello()" />
<input type="button" value="모듈1 로딩 및 실행" onclick="loadingModule1AndRun()" />
</body>

위 코드에서 sayHello() 함수는 module1.js에 정의되어 있다. 따라서 module1.js를 로딩하기 전에 sayHello() 함수를 실행하면 에러가 발생하게 된다.

loadingModule1AndRun() 함수가 실행되면, 동적으로 module1.js 스크립트를 로딩한다. module1.js 스크립트가 완전히 로딩되면 콜백으로 전달한 runModule1() 함수가 실행된다. 일단 module1.js 스크립트가 로딩되면 sayHello() 함수를 실행할 수 있으므로, 콜백 함수로 실행되는 runModule1()에서 sayHello() 함수를 실행하면 정상적으로 동작하게 된다.

결론

동적으로 자바 스크립트를 로딩함으로써 얻을 수 있는 이점은 다음과 같다.

  • 초기 구동에 필요하지 않은 자바 스크립트 파일을 로딩하지 않기 때문에, 웹 페이지를 빠르게 로딩할 수 있다.
  • 자바 스크립트를 알맞은 단위로 모듈화하도록 유도한다.

주의해야 할 점은 동일한 자바 스크립트 파일을 중복해서 로딩하지 않게 주의해야 한다는 점이다. 이 부분은 한번 직접 고민해 보기 바란다. 힌트는 아래와 같다.

  • 동일한 함수명을 사용하는 방법
  • loadJavaScript 함수를 한번 래핑해서 방지하는 방법

관련 링크:


출처 : 자바캔