동적 스크립트 로더 LAB.js

January 29, 2015

LABjs (Loading And Blocking JavaScript)

NOTE: LABjs는 지속적으로 관리되고 있으며 여전히 당신의 프로젝트에 사용해도 무방한 오픈소스이다. 하지만 버그 수정 이외의 개발은 없을 예정이다. LABjs는 거의 4년이 되었다. 그리고 버그 수정 및 패치한지 2년이 되어갈만큼 안정적이다. 지난 4년간 이 프로젝트를 지원해준 커뮤니티에 감사를 표한다.

LABjs는 동적 스크립트 로더이다. 유연하고 성능에 최적화된 대체 API를 제공한다. LABjs의 특징은 브라우저가 허용하는 범위에서 최대한 빨리 모든 자바스크립트 파일을 병렬로 로드한다는 것이다. 그러면서도 서로 의존관계에 있는 파일의 실행 시점을 확실히 하기 위해서 옵션을 제공한다.

일반적인 예:

<script src="http://remote.tld/jquery.js"></script>
<script src="local/plugin1.jquery.js"></script>
<script src="local/plugin2.jquery.js"></script>
<script src="local/init.js"></script>
<script>
  initMyPage();
</script>

LABjs :

<script src="LAB.js"></script>
<script>
  $LAB
  .script("http://remote.tld/jquery.js").wait()
  .script("/local/plugin1.jquery.js")
  .script("/local/plugin2.jquery.js").wait()
  .script("/local/init.js").wait(function(){
      initMyPage();
  });
</script>

두 스니펫의 차이는 이렇다. 일반적인 스크립트 태그의 경우 스크립트의 로딩과 실행을 조절할 수 없다. 최근의 브라우저는 스크립트를 병렬로 로드하지만 실행은 직렬로 한다. 먼저 선언된 스크립트에 의존적인 보다 작은 스크립트는 로딩이 빠를수도 있지만 그렇다고 이를 지연시키지도 않는다.

오래된 브라우저는 한번에 하나씩 로드하고 실행한다. 당연히 병렬 로딩 스피드의 장점을 잃어버리는 것이며 전체 프로세스의 속도를 크게 저하시킨다. 하지만 모든 브라우저는 스크립트가 로딩되는 동안 스타일시트나 이미지들은 차단한다. 그래서 페이지 로딩의 남은 부분은 사용자에게 훨씬 더 느리게 나타난다.

이와는 대조적으로 LABjs는 모든 스크립트를 병렬로 로드하며 .wait() 함수를 통해 의존관계를 설정하지 않는 한 가능한한 빨리 실행을 한다. 게다가 .wait(...) 안에는 로드가 끝난 시점에 실행할 인라인 스크립트 로직을 작성할 수도 있다.

이를 깨닫는 것은 매우 중요하다. 각각의 $LAB 체인은 독립적으로 운영된다. 다시 말하면 체인간에는 실행 순서를 기다리지 않는다.

NOTE: 자바스크립트의 실행은 여전히 싱글 스레드, first-come-first-served 환경이다. 그래서 어떤 브라우저는 각 체인의 스크립트 실행을 막는 인터널 로딩 큐를 만들기도 한다.

그리고 AllowDuplicates:false 설정 옵션은 체인간 중복을 허용하지 않는다. 이것의 의미는 체인 B는 체인 A를 대기하도록 만들 수 있다는 것이다. 만약 체인 B가 체인 A와 동일한 스크립트 URL을 레퍼런스로 참조하고 있고, 그 스크립트가 아직 로딩중이라면 말이다.

Build Process

공식적인 빌드 프로세스나 스크립트는 없다. 하지만 LAB.min.jsLAB-debug.min.js 파일을 만들었던 방법을 BUILD.md에 적어놓았다.

Configuration

전역으로 혹은 체인마다 정의할수 있는 설정 옵션이 있다.

$LAB.setGlobalDefaults({AlwaysPreserveOrder:true});

위와 같은 경우는 모든 $LAB 체인에 함축적으로 .wait()을 인서트 하게끔 한다. 동작은 각각의 .script() 사이에 수동으로 .wait()을 입력하는 것과 동일한 효과를 얻는다.

$LAB.setOptions({AlwaysPreserveOrder:true}).script(...)...

위의 경우는 부분적인 $LAB 체인에 적용된다.

활용 가능한 추가적인 옵션으로는 다음과 같은 것이 있다.

  • UseLocalXHR : true/false (default true): 같은 도메인의 스크립트를 사전에 로드하는데에 XHR 사용
  • AlwaysPreserveOrder: true/false (default false): 스크립트 로드 요청 후에 .wait()을 자동으로 인서트 할 것인지 결정하는 옵션. 만약 사용하기로 한다면 로드된 파일이 즉시 실행되는 것을 방지한다. 모든 스크립트가 로딩될 때 까지 기다린다.
  • AllowDuplicates: true/false (default true): 만약 같은 스크립트 URL이 이미 요청되었을 때 $LAB 로딩 캐시를 검사하는 것이 true, 무시하고 다시 로드하는 것이 false 옵션이다.
  • CacheBust: true/false (default false): 스크립트 URL 마지막에 랜덤으로 생성한 숫자를 붙여서 캐싱을 한다.
  • BasePath: {string} (default ""): 모든 스크립트 URL 앞에 붙이는 패스 스트링 설정 옵션

Protocol-relative URLs

브라우저는 오래전부터 “http:” 혹은 “https:”를 없애고 “//domain.tld/path/…“식으로 쓸 수 있도록 Protocol-relative URLs을 지원했다. 이렇게 설정하면 호출하는 페이지의 프로토콜과 동일한 것으로 호출을 한다. 장점은 프로토콜 변경으로부터 자유로워진다는 것이다. LABjs는 스크립트 URL을 셋팅할 때에도 이를 지원한다.

New in v2.0

  • 이제 AllouwDuplicates 옵션은 체인간에 확실히 동작한다. 이 사항은 의존성을 공유하고 있는 다수의 중첩된 $LAB 체인의 동작하는 매커니즘에서 매우 중요한 부분이다.
  • 체인을 멈췄다가 다시 시작할 수 있다. 이것의 의미는 체인 마지막 함수의 리턴 벨류를 저장할 수 있고, 저장된 값은 남은 체인이 시작되는 시점에 사용할 수 있다는 의이미다.
  • QueueingqueueScript, queueWait 그리고 runQueue와 함께 이제 빌트인이다.
  • LABjs는 이제 noConflict를 지원한다.
  • LABjs now relies on feature-testing for async=false and implicit/explicit “true preloading” (currently only IE, but in the spec process). Ugly/hacky “cache preloading” is now only used for “older webkit” (before March 2011 nightlies, etc), and even then, only for remote files.
  • For XHR preloading (only used in “older webkit” for local files, by default), to support better debugability, “// @sourceURL=…” is appended to the end of the code, to map the XHR/injected code to a real file name. Currently, browsers only support this for eval() (not script injection, like LABjs uses). It is hoped that browsers will soon support this annotation for their developer-tools.
  • Speaking of debugging, LABjs now supports a DEBUG mode (only if you use the source file, or if you use the LABjs-debug.min.js production file) and enable the “Debug” config option, which captures all the inner workings (and any errors in .wait() calls) to the browser’s console.log, if present.
  • LABjs now supports a “CacheBust” config option, which will attempt to make sure all loaded scripts are forcibly loaded new on each page refresh, by auto-appending a random number parameter to each URL. **This is really only practical/advised for DEV environments, where you want to ensure that the code reloads every time. Doing so in production would be really bad for user performance.***
  • As part of LABjs’ rewrite, the code style is now significantly improved in readability (most “minification” hacks have been removed), and it’s also using more memory-savvy code, such as far fewer closures. As a result, LABjs should run leaner and faster, if only by a little bit. The goal is to get LABjs out of the way so your scripts load and run as fast as possible.
  • “AppendTo”, “UsePreloading”, and “UseCachePreloading” options were removed as they are no longer useful. This is the only backwards-incompatible change (no actual API changes, just config), and the change should just cause older usage code to continue to operate as normal while ignoring the no longer supported options. Still, test your code carefully if you’ve been using either of those 3 config options before.

Comments

comments powered by Disqus