Develop
2013.04.23 16:18
[js] 자바스크립트를 동적으로 로딩하기
조회 수 13616 댓글 0
Dynamic Script Loading
동적으로 자바스크립트를 로딩하는 방법 중 하나는 script 태그를 자바스크립트 코드에서 직접 생성하는 것인데요. 다음과 같이 script 태그를 생성하고 src에 로딩할 주소를 넣음으로서 로딩하게 됩니다.
var head= document.getElementsByTagName('head')[0]; var script= document.createElement('script'); script.type= 'text/javascript'; script.src= 'helper.js'; head.appendChild(script)
위의 코드를 실행함으로서 스크립트 파일을 로딩을 할 수는 있지만, 스크립트가 로딩이 완료되어서 사용할 수 있는 지 여부를 알 수가 없습니다. 이 때 사용할 수 있는 방법은 두 가지가 있습니다.
하나는, script 태그의 onload 속성을 사용하는 것과
또 다른 하나는, 로딩하는 스크립트 파일안에 자신이 로딩되었음을 알려주는 코드를 넣는 방법입니다.
1에서의 문제점은 IE에서는 script 태그에서의 onload를 지원하지 않는다는 점인데요. MSDN에는 attributes에 포함되어 있기는 합니다만 호출되지는 않습니다.
대신에 IE에서 지원하는 onreadystatechange(비표준)를사용하면 script태그에서 로딩이 완료되었는지 여부를 알 수 가 있습니다.
var head= document.getElementsByTagName('head')[0]; var script= document.createElement('script'); script.type= 'text/javascript'; script.onreadystatechange= function () { if (this.readyState == 'complete' || this.readyState == 'loaded') helper(); } script.onload= helper; script.src= 'helper.js'; head.appendChild(script)
※ IE에서 onreadystatechange를 사용하여 로딩을 체크하는 상태 값으로 'loaded' 또는'complete'가 호출되기 때문에 두 값중 하나를 체크해서 실행하도록 합니다.
※※ 두 번 호출될 수도 있기 때문에 해당하는 부분에 대해서는 중복로딩이 되지 않도록 처리를 해야합니다.
2의 문제점은 동적으로 로딩하려는 코드의 뒤에 로딩되었음을 알려주는 동작이 추가되어야 하는 문제점이 있습니다. script 태그를 사용하지 않고 다른 방법으로도 로딩은 가능합니다.
가장 대표적인 방법으로 XMLHTTPRequest를 사용하는 방법인데요. 사용방법은 다 아실테니 생략하도록 하겠습니다. ^^;;; 파일을 요청한 후, 요청한 파일을 response로 받은 다음 이를 eval()를 사용하여서 로딩하게 되는데요. 파일을 로딩하는게 아니라 파일을 텍스트로 로딩한 후, 이를 실행하기 때문에
일반적인 자바스크립트 파일이 브라우저에서 캐시가 되지만 텍스트에 대해서는 캐시할 수 없습니다.
에러가 발생하여도 몇 번째 줄에서 발생하였는 지에 대한 정확한 정보를 얻기 힘듭니다.
이 외에도 iframe을 사용하여 로딩을하거나 document.write()를 쓸 수도 있겠죠.
Degrading Script Tags
Steve Souders의 Coupling asynchronous scripts에서는 조금 다른 방식을 취합니다. 먼저, 이 방식을 들여다보기 전에, 위대하신 레식 사마의 Degrading Script Tags에 대해서 살펴봐야 하는데요.
아래와 같이 외부 파일 형태로 존재하는 자바스크립트 파일과 이를 사용하는 코드를
<script src="some-lib.js"></script> <script> var foo = use_some_lib(); foo.do.stuff(); </script>
다음과 같이 하나의 script 태그로 묶습니다.
<script src="some-lib.js"> var foo = use_some_lib(); foo.do.stuff(); </script>
그리고, some-lib.js의 파일 안에 some-lib.js를 로딩하는 script 태그 안의 자바스크립트 코드를 실행하는 코드를 추가합니다.
var scripts = document.getElementsByTagName("script"); eval( scripts[ scripts.length - 1 ].innerHTML );
이렇게 묶게 되면 some-lib.js에 정의되어 있는 코드와 이를 사용하는 코드를 하나로 묶을 수 있기 때문에 some-lib.js를 로딩하는데 실패하게 되는 경우, 사용하는 코드도 함께 실행하지 않게 할 수 있는 장점(Degrading)이 있습니다.
Degrading Script Tags는 script 태그의 다음 특성을 사용합니다.
script 태그에 src 속성이 포함되어 있는 경우, script 태그 사이에 정의되어 있는 자바스크립트 코드는 실행되지 않습니다.
그러나, script 태그도 HTMLElement이기 때문에 innerHTML로 script 태그안에 정의되어 있는 코드에 접근이 가능합니다.
Coupling asynchronous scripts
Steve Souders는 Script 태그를 사용하여 동적으로 로딩하는 방식에 Degrading Script Tags를 함께 사용하여, 관련된 코드들을 하나로 묶어버립니다.
var script = document.createElement('script'); script.src = "sorttable-async.js"; script.text = "sorttable.init()"; document.getElementsByTagName('head')[0].appendChild(script);
sorttable-async.js에 정의되어 있는 코드를 호출하는 코드를 script태그의 text에 넣어서 커플링을 최소화 시킨 후, sorttable-asnyc.js의 뒤에 script 코드를 실행하는 코드를 추가하여 외부 파일의 코드가 로딩된 후, 바로 실행되게 합니다.
var scripts = document.getElementsByTagName("script"); var cntr = scripts.length; while ( cntr ) { var curScript = scripts[cntr-1]; if ( -1 != curScript.src.indexOf('sorttable-async.js') ) { eval( curScript.innerHTML ); break; } cntr--; }
Steve Souders는 위의 코드처럼 초기에 로딩될 필요가 없는 자바스크립트 코드의 로딩을 동적으로 로딩되게 한 후, 페이지가 전체 로딩된 다음에 실행될 코드들을 window의 onload() 시 호출되도록 조정하여 Stuart Langridge의 sorttable script의 로딩 속도를 487ms에서 417ms까지 단축시켰습니다.
[출처]
Jan Wolter - JavaScript Madness: Dynamic Script Loading
John Resig - Degrading Script Tags
Steve Souders - Coupling asynchronous scripts
※ Steve Souders가 Coupling asynchronous scripts 다음으로 쓴 Loading Scripts Without Blocking 글도 함께 보시면 도움이 많이 될 것 같습니다.
번호 | 분류 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|---|
673 | Develop |
GPL, AGPL, MPL,.. 한눈에 보는 오픈소스SW 라이선스
![]() |
hooni | 2014.10.14 | 1274 |
672 | Develop | [js] 좋은 강연자료 & UI 자료 | hooni | 2014.10.06 | 997 |
671 | Develop |
'2014 모바일 개발 트렌드' 발표자료입니다.
![]() |
hooni | 2014.10.02 | 1142 |
670 | Develop |
[ios] iOS 8 개발자가 우선 알아야 할 3가지
![]() |
hooni | 2014.10.02 | 993 |
669 | Develop |
[js] jQuery 셀 병합
1 ![]() |
hooni | 2014.09.23 | 3569 |
668 | Develop | [ios] Xcode cannot run using the selected device | hooni | 2014.08.14 | 1929 |
667 | Develop | [ios] Objective-C 에서 자주 사용하는 수학 함수와 유용한 Define | hooni | 2014.08.08 | 2003 |
666 | Develop |
[ios] 카테고리 확장 메소드를 찾지 못하는 경우
![]() |
hooni | 2014.08.08 | 2123 |
665 | Develop | [ios] @property의 속성 (strong, weak, copy) 사용 경우 | hooni | 2014.08.08 | 1782 |
664 | Develop | [ios] TextField 특정 문자만 사용하도록 하기 | hooni | 2014.06.30 | 2797 |
663 | Develop | [ios] XCode에서 Provisioning Profile 여러개 중복될 때 | hooni | 2014.06.26 | 2953 |
662 | Develop | 알고리즘 성능 분석 기준 | hooni | 2014.06.24 | 2920 |