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

스프링5 입문

JSP 2.3

JPA 입문

DDD Start

인프런 객체 지향 입문 강의

Ajax로 읽어온 JSON 데이터로부터 HTML을 생성해주어야 하는 경우에 사용하기 좋은 문자열 템플릿 처리 라이브러리를 찾다가, jQuery 플러그인인 nano를 발견했다. jQuery nano 플러그인은 매우 간단한 라이브러리로서 아래 사이트에서 다운로드 받을 수 있다.

  • https://github.com/trix/nano

jQuery 1.9.1을 사용하고 있는데, 동작하지 않아 다음과 같이 코드를 일부 수정하였다. (빨간색으로 표시한 부분 삭제 처리, 다른 jQuery 버전에서는 어떻게 동작하는지 확인해보진 않았다.)


/* Nano Templates (Tomasz Mazur, Jacek Becela) */


(function($) {

    var _regex = /\{([\w\.]*)\}/g;

    $.fn.nano = function(template, data) {

        return template.replace(_regex, function (str, key) {

            var keys = key.split('.'), value = data[keys.shift()];

            $.each(keys, function() { value = value[this]; });

            return (value === null || value === undefined) ? '' : value;

        });

    };

}(jQuery));


사용방법은 간단한다. 다음과 같이 jquery와 함께 jquery.nano.js를 <script>로 읽어온 뒤에 $.nano() 메서드를 사용해서 변환 처리를 하면 된다.


<script src="/js/jquery/jquery-1.9.1.min.js"></script>

<script src="/js/jquery/jquery.nano.js"></script>

<script>

var data = {

    content: {

        title: "제목",

        imageUrl: "/pds/1.png"

    },

    desc: "설명"

}

var html = $.nano("<div>{content.title}</div><img src='{content.imageUrl}' alt='{desc}' />", data);

</script>


위 코드에서 nano() 함수의 첫 번째 파라미터는 문자열 템플릿이며, 두 번째 인자는 템플릿에서 사용될 값을 갖는 JSON 객체이다. 문자열에 포함된 {변수명}은 JSON 객체의 해당하는 값으로 치환된다. 예를 들어, 위 코드에서 {content.title}은 data.content.title의 값으로 치환되며, {desc}는 data.desc로 치환된다. 따라서, 위 코드에서 $.nano() 함수의 실행 결과로 생성되는 문자열 html은 "<div>제목</div><img src='/pds/1.png' alt='설명' />"이 된다.


사용법이 매우 간단하면서도 Ajax로 읽어온 JSON 객체를 그대로 사용할 수 있다는 점에서 유용하다.

Posted by 최범균 madvirus

댓글을 달아 주세요

  1. 간세 2013.03.28 09:54 신고  댓글주소  수정/삭제  댓글쓰기

    오~ 굉장히 유용하겠네요.
    $('<div/>').attr(...).html(..).appendTo(..)
    이런코드가 확 줄겠네요..
    좋은 정보 감사합니다. 꾸벅.

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 파일을 동적으로 로딩하는 방법이 필요했는데 정말 좋은 내용 감사합니다. 잘 보고 갑니다~