저작권 안내: 저작권자표시 Yes 상업적이용 No 컨텐츠변경 No

스프링5 입문

JSP 2.3

JPA 입문

DDD Start

인프런 객체 지향 입문 강의

'Dynamic Javascript Loading'에 해당되는 글 1건

  1. 2008.12.11 자바 스크립트 동적 로딩 (5)

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 함수를 한번 래핑해서 방지하는 방법

관련 링크:

Posted by 최범균 madvirus

댓글을 달아 주세요

  1. Shrek 2008.12.13 17:24 신고  댓글주소  수정/삭제  댓글쓰기

    if (this.readyState == 'loaded' || this.readyState == 'complete') {
    if (loaded) { // 이건 언제 true가 되는건지?
    return;
    }
    loaded = true;
    callback();
    }

  2. 최범균 madvirus 2008.12.14 22:52 신고  댓글주소  수정/삭제  댓글쓰기

    위코드 보시면 if (loaded)를 실행한 이유는 'loaded'를 통해서 loaded가 true가 되었는데, 또 'complete'가 발생해서 함수가 다시 실행되는 경우를 대비한 코드에요.

  3. 지나가는 행인 2013.07.11 11:30 신고  댓글주소  수정/삭제  댓글쓰기

    안녕하세요 보여주신 코드 참고해서 css 동적로딩 함수를 만들어봤는데 이게 맞나요?
    -------------------------------------------------------------------------
    function loadCss(url, callback, charset) {
    var head= document.getElementsByTagName('head')[0];
    var css= document.createElement('link');
    css.type= 'text/css';
    css.rel = "stylesheet";
    if (charset != null) {
    css.charset = "euc-kr";
    }
    var loaded = false;
    css.onreadystatechange= function () {
    if (this.readyState == 'loaded' || this.readyState == 'complete') {
    if (loaded) {
    return;
    }
    loaded = true;
    callback();
    }
    }
    css.onload = function () {
    callback();
    }
    css.href = url;
    head.appendChild(css);
    }
    ---------------------------------------------------------------------

    • 최범균 madvirus 2013.07.12 14:05 신고  댓글주소  수정/삭제

      제가 이 방식으로 CSS도 동적으로 읽어와 적용할 수 있는지 여부를 몰라서, 뭐라고 정확하게 말씀을 못 드리겠습니다만,
      jQuery 이용시, 아래와 같은 코드를 사용해보라는 것을 어디선가 본 것 같습니다.

      <script>
      $(document).ready( function() {
      $('').appendTo('head').attr({rel: 'stylesheet',type: 'text/css',href: 'dynamic.css'});
      });
      </script>

  4. 토토땅 2014.09.05 10:27 신고  댓글주소  수정/삭제  댓글쓰기

    js 파일을 동적으로 로딩하는 방법이 필요했는데 정말 좋은 내용 감사합니다. 잘 보고 갑니다~