JavaScript 파일을 웹페이지에 추가하는 방법은 여러 가지가 있는데, 과거엔 주로 head tag에다 추가해 줄 때가 많았으나, 이렇게 하면 브라우저가 JavaScript 파일을 다 읽어 들이는 동안 웹페이지의 렌더링이 잠깐 멈추게 되는 부작용이 있어서, 최근엔 웹페이지를 되도록 빠르게 화면에 뿌려주려고 body tag 마지막에 얹어 주는 것을 권장하고 있다.

그런데 최근 날로 웹 애플리케이션의 개발과 그 활용 방법론이 많이 알려지면서 JavaScript 파일이 점점 더 커지는 경향이 있는데, 무조건 내려받게 되는 이런 JavaScript 파일의 용량을 조금이라도 줄이려는 노력도 따라서 필요해진다. 그래서 페이지에 얹어진 JavaScript 파일 중에 특정 기능이 빈번히 사용되지 않고 특별한 경우에만 쓰이는 것이라면, 이마저도 주요 JavaScript 파일에서 빼어내 특정 조건에 따라 필요할 때만 로딩해주는 기술이 쓰일 수 있다.

jQeury에선 이럴 때에 꼭 안성맞춤인 jQuery.getScript() 함수를 제공하고 있는데, 사용법은 다음과 같다.

$.getScript("ajax/test.js", function(datatextStatusjqxhr) {
   console.log(data); //data returned 
   console.log(textStatus); //success 
   console.log(jqxhr.status); //200 
   console.log('Load was performed.');
});

jQuery를 쓰지 않고 일반 JavaScript로 구현하려면 javascript_loader.js를 참고해서 구현해 볼 수도 있다.
웹페이지 로딩 후, 필요할 때에만 특정 JavaScript 파일을 읽어 들이는 방법(이)란 제목의 글 마저 읽기 →

IE6,7,8에게 새 HTML5 elements를 인식시켜주는 html5shiv를 문서에 추가하는 방법으로 보통 head에서 다음과 같이 불러온다.

<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->

문젠 그냥 이렇게 html5shiv를 googlecode에서 불러오면 성능상 별로 안 좋다는 얘기.
이렇게 추가된 script는 HTTP compression 되지도 않았거니와 CDN을 사용하면 당연히 얻겠거니 하는 cache 적용도 되어있지 않다. (현재 겨우 180초뿐이다.)

더군다나, 현재 공식 배포 채널로 사용되긴 하지만, 버그도 잡고 성능이 향상된 최신 버전으로의 적용도 더뎌서 github에서 활발히 개발되고 있는 html5shiv의 최신 버전(현재 Tag 3.5)을 내려받아 compress(minified)한 후 직접 호스팅하는 편이 여러모로 더 이롭다는 얘기.

참고로, Modernizr를 쓴다면 이미 core에 포함되어 있기 때문에 따로 추가할 필요는 없으며, 최신 버전도 곧 적용될 예정이란다. 끝으로 “절대 다른 사람의 source code repository에 있는 리소스에 직접 링크를 걸지는 마라”는 경고로 말을 맺고 있음.

switch(foo) {
  case 'alpha':
    // do X 
    break;
  case 'beta':
    // do Y 
    break;
  default:
    // do Z 
    break;
}

위와 같은 구문을 다음처럼 Object notation을 써서 약간 더 빠르게 실행될 수 있도록 구현할 수 있다.

var switchObj = {
  'alpha'function() {
    // do X 
  },
  'beta'function() {
    // do Y 
  },
  '_default'function() {
    // do Z 
  }
};
(switchObj.hasOwnProperty(foo) && switchObj[foo] || switchObj._default)(args);

물론 비교 대상의 case가 별로 많지 않을 땐 속도의 차이는 크게 나지 않는다.

따온 곳 – How DRY Affects JavaScript Performance — Faster JavaScript Execution For The Lazy Developer

JavaScript 파일은 페이지 로딩 속도 측면에서 페이지의 body가 닫히기 바로 전에 추가해 주는 것이 가장 좋은데, WordPress에 기본적으로 추가된 jQuery는 꼭대기 head 부분에 붙어 있다.

이놈을 맨 아랫부분에 추가하려면, 테마 파일에 있는 functions.php 파일을 열고 WordPress의 wp_register_script()wp_enqueue_script() function을 사용하는 다음과 같은 코드를 추가해 준다.

<?php
function my_scripts_enqueue() {
  wp_deregister_script('jquery');
  wp_register_script('jquery'"http" . ($_SERVER['SERVER_PORT'] == 443 ? "s" : "". '://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'falseNULLtrue);
  wp_enqueue_script('jquery');
}
 
if (!is_admin()) add_action('wp_enqueue_scripts''my_scripts_enqueue'11);
?> 

여기에 있는 wp_register_script() function의 parameter 중 네 번째와 다섯 번째가 중요한 요소인데, 각각 $ver$in_footer 변수를 의미한다.

$ver 변수는 보통 JavaScript 파일 경로의 마지막 부분에 query string처럼 붙으면서 JavaScript 파일이 갱신되었을 때 caching된 것의 사용을 막으려고 사용되는데, jQuery처럼 Google CDN에서 불러올 때는 오히려 방해되므로 NULL 값을 줘서 없애버린다. 그리고 $in_footer 값에 true를 주면 JavaScript가 body 맨 마지막 부분에 붙게 된다.

내용 갱신(2014년 6월 25일): 현재 설치된 WordPress 3.9.1 버전에선 위에서 설명했던 방법이 제대로 적용되질 않아서, 해결책을 검색한 결과 다음 페이지에서 해답을 얻을 수 있었다.: Unable to move wordpress jquery library into the footer – Stack Overflow

그래서, 가령 jQuery를 Google에서 호스팅하고 있는 것으로 바꿔서 페이지 마지막 부분에 추가해 주려면 functions.php 파일에 다음과 같이 등록해 준다.

<?php
function my_footer_enqueue_scripts() {
    remove_action('wp_head''wp_print_scripts');
    remove_action('wp_head''wp_print_head_scripts'9);
    remove_action('wp_head''wp_enqueue_scripts'1);
    wp_deregister_script('jquery');
    wp_register_script('jquery'"http" . ($_SERVER['SERVER_PORT'] == 443 ? "s" : "". '://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'falseNULLtrue);
    wp_enqueue_script('jquery');
}
 
if (!is_admin()) add_action('wp_enqueue_scripts''my_footer_enqueue_scripts');
?> 

나중에, Google에서 호스팅하고 있는 jQuery 버전이 갱신된다면, 위 코드에 작성된 jQuery의 호스팅 주소 중에 버전에 해당되는 부분만 새 것으로 바꿔주면 된다.

WebKit nightly builds가 HTML5 표준에 정의되어 있는 script 요소의 async와 defer 속성을 지원하기 시작했다는 소식.

기본적으로 웹 브라우저가 외부 자바스크립트를 불러오는 일반 script 태그를 만나게 되면, 우선 해당 스크립트를 내려받아 해석하고 실행(execute)할 때까지 웹 문서의 HTML 코드 parsing 작업을 잠시 뒤로 미룬다. 그래서 용량이 큰 스크립트를 문서 해석 초기에 만나게 되면 해당 페이지를 불러오는 속도마저 지체되는 현상을 일으키게 되어 결국 전체적 성능을 떨어뜨리는 결과를 가져오는데, 이런 성능의 병목 현상을 막기 위해 여러 다양한 꼼수들이 쓰여왔다. 이런 부작용을 근본적으로 막기 위해 소개된 것이 script 태그의 async와 defer 속성이다.

사용 예를 보면 아주 단순하다:

<script async src="myAsyncScript.js" onload="myInit()"></script>
<script defer src="myDeferScript.js" onload="myInit()"></script>

위와 같이 async 혹은 defer 된 스크립트는 문서 parsing 작업의 중단 없이 동시에 내려받게 되며, 선택적으로 onload handler를 지정해서 일반적인 초기화 작업도 진행할 수 있다.
둘의 차이를 결정짓는 중요한 것은 바로 스크립트가 실행되는 시점이 서로 다르다는 것인데, async script는 window의 load event 전 내려받는 즉시 바로 실행되는 데 반해 defer script는 문서의 parsing 작업이 끝난 후 DOMContentLoaded event 전에 문서에 삽입된 순서에 따라 실행된다.

둘의 JavaScript 실행 시점의 차이는 Peter Beverloo씨가 그린 도표를 보면 훨씬 더 명확해진다.

script가 문서를 직접 만지고 조작하거나 서로 간 로딩 순서가 중요할 때에는 defer 속성을 쓰고, 그렇지 않다면 async 속성을 써서 웹 페이지 로딩 속도를 줄일 수 있다.

앞으로 WebKit 기반 브라우저가 이 속성을 모두 지원할 예정이라지만, 이미 Firefox는 3.6 버전부터 두 속성 모두를 지원하고 있으며, Internet Explorer 역시 예전부터 defer 속성을 지원하고 있었으나 async 속성은 아직 지원하지 않는다.

결국, 큰 용량의 JavaScript로 말미암은 페이지 로딩 지체 현상을 방지하려면 두 속성의 지원 상황이 나아질 때까지 아직 꼼수가 필요하다. – 웹 브라우저의 async와 defer 속성 지원 여부 알아보기.

덧붙임(2011-2-3): HTML5 spec에 async=false 속성을 쓰면 스크립트가 삽입된 순서대로 실행되도록 하는 기능이 추가됨. async 속성의 기본값은 true.