로그인

이메일
비밀번호
왼쪽에 걸리적 거리는 거 숨기기

원문은 여기서 보세요.

Loading Scripts Without Blocking

블록킹 없이 스크립트 로딩하긔

 

April 27, 2009 10:49 PM

 

This post is based on Chapter 4 from Even Faster Web Sites, the follow-up to High Performance Web Sites. Posts in this series include: chapters and contributing authors, Splitting the Initial Payload, Loading Scripts Without Blocking, Coupling Asynchronous Scripts, and Positioning Inline Scripts.

 

As more and more sites evolve into “Web 2.0″ apps, the amount of JavaScript increases.

사이트가 Web 2.0 어플 형태로 개발 될수록, JavaScript 의 양은 늘어납니다.

 

This is a performance concern because scripts have a negative impact on page performance.

스크립트는 페이지 성능에 안 좋은 영향을 끼치기 때문에 이는 성능 문제를 야기 시킬 수 있습니다.

 

Mainstream browsers (i.e., IE 6 and 7)  block in two ways:

주류 브라우저(IE6, 7 같은)에서 블록 될 수 있는 경우에는 두 가지가 있습니다.

  • Resources in the page are blocked from downloading if they are below the script.
  • 스크립트 내에 있는 페이지의 리소스가 다운로드 때문에 블록 된 경우
  • Elements are blocked from rendering if they are below the script.
  • 스크립트 내에 있는 엘리먼트의 렌더링 때문에 블록 된 경우

 

The Scripts Block Downloads example demonstrates this.

여기 Scripts Block Downloads 예제 가 있습니다.

 

It contains two external scripts followed by an image, a stylesheet, and an iframe.

이 예제는 두 개의 외부 스크립트에 이어서 이미지, CSS, IFRAME 을 포함하고 있는데요,

 

The HTTP waterfall chart from loading this example in IE7 shows that the first script blocks all downloads, then the second script blocks all downloads, and finally the image, stylesheet, and iframe all download in parallel.

이 예제를 IE7 에서 돌렸을 때의 HTTP 전송상황을 보면 맨 처음 스크립트의 다운로드가 끝날 때까지 블록 됨을 확인 할 수 있습니다. 그리고 나서 두번째 스크립트도 다운로드가 끝날 때까지 블록됩니다. 마지막으로 이미지, CSS, IFRAME 은 다운로드가 병렬적으로 진행됩니다.

 

Watching the page render, you’ll notice that the paragraph of text above the script renders immediately.

페이지 렌더링 되는 걸 보면 스크립트 위에 있는 텍스트 문장은 즉시 렌더링 되는 걸을 확인 할 수 있습니다.

 

However, the rest of the text in the HTML document is blocked from rendering until all the scripts are done loading.

하지만 HTML 문서의 나머지 텍스트는 스크립트 로딩이 모두 끝날 때까지 렌더링이 되지 않고 블록됩니다.

 

사용자 삽입 이미지

Scripts block downloads in IE6&7, Firefox 2&3.0, Safari 3, Chrome 1, and Opera
IE6~7 Firefox 2~3, Safari 3, Chrome 1, Opera 에서의 스크립트 다운로드

 

Browsers are single threaded, so it’s understandable that while a script is executing the browser is unable to start other downloads.

스크립트가 실행되는 동안 브라우저가 다른 다운로드를 시작하는 것이 불가능하다는 것은 브라우저가 싱글 쓰레드로 동작하기 때문에 이해가 되는 부분입니다.

 

But there’s no reason that while the script is downloading the browser can’t start downloading other resources.

하지만 스크립트가 다운로드 되는 동안 브라우저가 다른 리소스의 다운로드를 시작하는게 불가능 하다는 건 이해가 되질 않습니다.

 

And that’s exactly what newer browsers, including Internet Explorer 8, Safari 4, and Chrome 2, have done.

최근의 브라우저인 IE8, Safari 4, Chrome 2 에서는 이러한 문제가 수정되었습니다.

 

The HTTP waterfall chart for the Scripts Block Downloads example in IE8 shows the scripts do indeed download in parallel, and the stylesheet is included in that parallel download.

앞서 봤던 에제 IE8 에서 돌려보고 HTTP 전송상황을 보면 스크립트의 다운로드가 병렬적으로 진행되고, CSS 도 동시에 다운로드가 진행되는 것을 볼 수 있습니다.

 

But the image and iframe are still blocked. Safari 4 and Chrome 2 behave in a similar way.

하지만 이미지나 IFRAME 은 여전히 블록됩니다. Safari 4 Chrome 2 도 마찬가지입니다.

 

Parallel downloading improves, but is still not as much as it could be.

병렬 다운로드 기능이 향상되긴 했지만 아직 좀 부족합니다.

 

사용자 삽입 이미지

Scripts still block, even in IE8, Safari 4, and Chrome 2

IE8, Safari 4, Chrome 2 에서도 스크립트가 블록됨

 

Fortunately, there are ways to get scripts to download without blocking any other resources in the page, even in older browsers. Unfortunately, it’s up to the web developer to do the heavy lifting.

다행히도 페이지 내에 있는 어떠한 리소스라도 블록 없이 스크립트를 로딩할 수 있는 몇 가지 방법이 있습니다.

 

There are six main techniques for downloading scripts without blocking:

블록 없이 스크립트를 다운로드 받은 수 있는 방법은 크게 6가지 입니다.

  • XHR Eval - Download the script via XHR and eval() the responseText.
  • XHR Eval - 스크립트를 XHR 로 다운 받아서 responseText eval() 로 실행 시키는 방법
  • XHR Injection - Download the script via XHR and inject it into the page by creating a script element and setting its text property to the responseText.
  • XHR Injection - 스크립트를 XHR 로 다운 받아서 responseText 을 새로 만든 <SCRIPT> 엘리먼트 내의 text 프로퍼티로 집어 넣는 방법
  • Script in Iframe - Wrap your script in an HTML page and download it as an iframe.
  • Script in Iframe - 스크립트를 IFRAME 페이지 내에서 다운받는 방법
  • Script DOM Element - Create a script element and set its src property to the script’s URL.
  • Script DOM Element - <SCRIPT> 엘리먼트를 만들고 그거의 src 을 스크립트의 URL 로 지정하는 방법
  • Script Defer - Add the script tag’s defer attribute. This used to only work in IE, but is now in Firefox 3.1.
  • Script Defer - <SCRIPT> 태그에 defer 어트리뷰트를 지정하는 방법. 이 방법은 현재 IE FireFox 3.1 에서만 사용 가능하다.
  • document.write Script Tag - Write the <script src=""> HTML into the page using document.write. This only loads script without blocking in IE.
  • document.write Script Tag - <SCRIPT src=””> HTML 코드를 document.write 를 사용해 찍어주는 방법. 오직 IE 에서만 이 방법으로 블록 되는 걸 피할 수 있다.

 

You can see an example of each technique using Cuzillion.

Cuzillion 를 사용해서 각각의 방법에 대한 예제를 확인해 보면,

 

It turns out that these techniques have several important differences, as shown in the following table.

아래 테이블에서 보여주는 것 처럼, 이러한 방법들은 몇가지 중요한 차이점을 가지고 있다는 걸 알 수 있습니다.

 

Most of them provide parallel downloads, although Script Defer and document.write Script Tag are mixed.

Script Defer document.write Script Tag 방법은 브라우저 마다 다르게 동작하기는 하지만 대부분의 방법은 사용 했을 때 병렬 다운로드가 가능하다.

 

Some of the techniques can’t be used on cross-site scripts, and some require slight modifications to your existing scripts to get them to work.

몇 가지 방법은 크로스-사이트 스크립트에서 사용할 수 없습니다. 그리고 몇 가지는 기존에 사용하던 스크립트를 약간 수정해야 합니다.

 

An area of differentiation that’s not widely discussed is whether the technique triggers the browser’s busy indicators (status bar, progress bar, tab icon, and cursor).

어떤 방법이 브라우저 로딩 중 상태(상태바나 로딩바, 탭 아이콘, 커서 같은)를 보여 주는지 여부에 대한 내용까지 넓게 논의 되지는 않았습니다.

 

If you’re loading multiple scripts that depend on each other, you’ll need a technique that preserves execution order.

만약 서로가 의존성을 가지고 있는 여러 개의 스크립트를 로딩해야 한다면, 스크립트의 실행 순서가 유지되는 방법이 필요합니다.

 

Technique

방법

Parallel Downloads

병렬 다운로드

Domains can Differ

도메인이 달라도 되나

Existing Scripts

Busy Indicators

로딩 중 표시 여부

Ensures Order

순서가 보장되나

Size (bytes)

사이즈

XHR Eval

IE, FF, Saf, Chr, Op

no

no

Saf, Chr

-

~500

XHR Injection

IE, FF, Saf, Chr, Op

no

yes

Saf, Chr

-

~500

Script in Iframe

IE, FF, Saf, Chr, Op

no

no

IE, FF, Saf, Chr

-

~50

Script DOM Element

IE, FF, Saf, Chr, Op

yes

yes

FF, Saf, Chr

FF, Op

~200

Script Defer

IE, Saf4, Chr2, FF3.1

yes

yes

IE, FF, Saf, Chr, Op

IE, FF, Saf, Chr, Op

~50

document.write Script Tag

IE, Saf4, Chr2, Op

yes

yes

IE, FF, Saf, Chr, Op

IE, FF, Saf, Chr, Op

~100

 

The question is: Which is the best technique?

그렇다면 어떤 것이 최선의 방법일까요?

 

The optimal technique depends on your situation.

바로 당신의 상황에 맞는 게 최선의 방법입니다.

 

This decision tree should be used as a guide.

여기 결정 Tree 가 도움이 될 수 있을 것 같습니다.

 

It’s not as complex as it looks.

생각보다 복잡하지 않습니다.

 

Only three variables determine the outcome: is the script on the same domain as the main page, is it necessary to preserve execution order, and should the busy indicators be triggered.

단지 세 개의 값들로 결정 짓습니다 : 스크립트가 메인 페이지에 대해서 같은 도메인에 있는지, 실행 순서가 지켜져야 되는지, 로딩 중 표시가 보여야 하는지


사용자 삽입 이미지

 

Ideally, the logic in this decision tree would be encapsulated in popular HTML templating languages (PHP, Python, Perl, etc.) so that the web developer could just call a function and be assured that their script gets loaded using the optimal technique.

이상적으로는 웹개발자가 가장 최적의 방법을 사용해서 스크립트를 읽어 들이는 것을 보장하고 함수를 호출하기 위해, 이러한 결정 Tree 에서의 논리는 가장 인기있는 HTML 템플릿 언어(PHP, Python, Perl )로 캡슐화 되어야 합니다.

 

In many situations, the Script DOM Element is a good choice.

많은 경우, Script DOM Element 를 사용하는 방법은 좋은 선택 입니다..

 

It works in all browsers, doesn’t have any cross-site scripting restrictions, is fairly simple to implement, and is well understood.

해당 방법은 크로스-사이트 스크립트 문제가 없이 모든 브라우저에서 잘 동작하고 구현하기 꽤 간단하며, 이해하기도 괜찮습니다..

 

The one catch is that it doesn’t preserve execution order across all browsers.

한 가지 아쉬운 점은 실행 순서를 유지 하는 것은 일부 브라우저에서만 지원한다는 점 입니다.

 

If you have multiple scripts that depend on each other, you’ll need to concatenate them or use a different technique.

만약 서로간 의존성을 가진 여러 개의 스크립트 파일을 사용하고 있다면, 그 파일들을 하나의 파일로 합쳐서 사용하거나, 아니면 다른 방법을 써야 하고,

 

If you have an inline script that depends on the external script, you’ll need to synchronize them.

외부 스크립트에 의존적인 inline 인라인 스크립트가 있다면, 스크립트 수행이 동시에 일어나야 합니다.

 

I call this “coupling” and present several ways to do this in Coupling Asynchronous Scripts.

저는 이걸 “coupling” 이라고 부르고요, Coupling Asynchronous Scripts 를 통해서 몇 가지 방법을 알려주고 있습니다.

영양가 있는 포스팅인가요
(총 4분이 투표해서 4.0점) 4.0점
2009/05/15 11:50 2009/05/15 11:50

우왕 여기 짱인듯.
http://reference.sitepoint.com/
닥치고 즐겨찾기.
영양가 있는 포스팅인가요
(총 1분이 투표해서 5.0점) 5.0점
2009/02/03 18:54 2009/02/03 18:54

일반적으로 JSON 스트링을 객체로 바꿀 때는 eval 을 사용합니다.
이를 테면 아래 처럼요.

(Language : javascript)
  1. var json = '{ hello : "world", foo : [ 1, 2, 3 ]}';
  2. var obj = eval('(' + json + ')');


그런데 오늘 회사동료가 저런식으로 반복해서 썼을때 파이어폭스3 에서 메모리 사용량이 치솟는 다고 하네요. 그래서 테스트로 한시간 정도 돌렸더니 마구 올라서 막 메모리를 몇 백메가씩 먹더군요-_-;

뭔가 파이어폭스3 의 버그인 것 같긴 한데 사용하는 입장에서 어찌 할 도리도 없고, 뭔가 회피 할 수 있는 방법이 없을까 이것저것 해보다가 아래처럼 했더니 (왜인지는 모르겠지만) 확실한 개선을 보여주었습니다.

(Language : javascript)
  1. function evalEx(sStr) {
  2.   return (new Function('', 'return ' + sStr + ';'))();
  3. }
  4.  
  5. var json = '{ hello : "world", foo : [ 1, 2, 3 ]}';
  6. var obj = evalEx(json);


문제도 해결하고 eval 쓸때 앞 뒤에 (, ) 도 안 붙혀줘도 되고, 괜찮은듯?

영양가 있는 포스팅인가요
(총 3분이 투표해서 5.0점) 5.0점
2008/10/14 14:56 2008/10/14 14:56

브라우저의 문서 영역의 크기를 구할때
현재 보여지는 부분의 크기(clientWidth, clientHeight)와
실제 존재하는 부분의 크기(scrollWidth, scrollHeight)를 사용하게 되는데,

이게, 브라우저마다 또 표준 DTD 인지 여부에 따라 구하는 방법이 모두 상이하다.
그래서 간단한 함수로 만들어봤다.

IE5, IE55, IE6, IE7, IE8, FF2, Safari3, Opera9 에서 테스트 됨 (Language : javascript)
  1. /**
  2. * 브라우저 document 영역의
  3. * clientWidth/clientHeight, scrollWidth/scrollHeight 구하기
  4. *
  5. * @author hooriza
  6. */
  7. function getClientSize() {
  8.  
  9.   var oDoc = document[document.compatMode == 'CSS1Compat' ? 'documentElement' : 'body'];
  10.   if (/Opera/.test(navigator.userAgent)) oDoc = document.body;
  11.  
  12.   return [
  13.     oDoc.clientWidth,
  14.     oDoc.clientHeight
  15.   ];
  16.  
  17. }
  18.  
  19. function getScrollSize() {
  20.  
  21.   var oDoc = document[document.compatMode == 'CSS1Compat' ? 'documentElement' : 'body'];
  22.   if (/Opera|Safari/.test(navigator.userAgent)) oDoc = document.body;
  23.  
  24.   // IE6 미만이면
  25.   if (/MSIE\s([0-9]+(\.[0-9]+)*)/.test(navigator.userAgent) && parseFloat(RegExp.$1) < 6) {
  26.    
  27.     var aOld = [ oDoc.scrollLeft, oDoc.scrollTop ];
  28.     var aClient = getClientSize();
  29.    
  30.     oDoc.scrollLeft = 999999;
  31.     oDoc.scrollTop = 999999;
  32.    
  33.     var aRet = [
  34.       oDoc.scrollLeft + aClient[0],
  35.       oDoc.scrollTop + aClient[1]
  36.     ];
  37.    
  38.     oDoc.scrollLeft = aOld[0];
  39.     oDoc.scrollTop = aOld[1];
  40.    
  41.     return aRet;
  42.    
  43.   }
  44.  
  45.   return [
  46.     oDoc.scrollWidth,
  47.     oDoc.scrollHeight
  48.   ];
  49.  
  50. }

IE5.5 이하의 경우는 당췌 scrollWidth, scrollHeight 가 제대로 얻어지질 않아서 꽁수를 사용했다;
영양가 있는 포스팅인가요
(총 4분이 투표해서 3.0점) 3.0점
2008/06/09 10:57 2008/06/09 10:57

주옥과 같은 자료
http://www.quirksmode.org/dom/events/index.html

존재조차 몰랐던 이벤트도 많이 있구나.
영양가 있는 포스팅인가요
(총 1분이 투표해서 2.0점) 2.0점
2008/05/16 22:15 2008/05/16 22:15

빠르게 클릭해도 문제가 생기지 않도록 만드는게 맞는 방향이긴 하지만,
여러가지 이유로 빠르게 클릭할 수 없게 만들고 싶은 경우 사용할 수 있는 스크립트이다.

몇 달 전에 만들었던 거.

(Language : javascript)
  1. function protectAbusing(oEl) {
  2.  
  3.   var key = oEl.getAttribute('_pabuse');
  4.   var bef = 0;
  5.  
  6.   if (!key) {
  7.  
  8.     key = 'U' + (new Date().getTime() * 1000000 + parseInt(Math.random() * 1000000));
  9.     oEl.setAttribute('_pabuse', key);
  10.    
  11.   } else {
  12.    
  13.     bef = arguments.callee._clickTimes[key];
  14.    
  15.   }
  16.  
  17.   var now = new Date().getTime();
  18.   arguments.callee._clickTimes[key] = now;
  19.  
  20.   // 마지막으로 클릭한지 1초가 넘었으면 true 리턴
  21.   return (now - bef) > 1000;
  22.  
  23. }
  24.  
  25. protectAbusing._clickTimes = {};

사용은 아래처럼 하면 된다.

(Language : html4strict)
  1. <a href="http://hooriza.com/" onclick="return protectAbusing(this);">

끝.
영양가 있는 포스팅인가요
(총 1분이 투표해서 5.0점) 5.0점
2008/05/14 15:13 2008/05/14 15:13

만드는 중간에 갈아엎은 것 까지 포함하면 대략 5번째 만드는 CSS 셀렉터 엔진.
맨 처음에 만들었던거는 아마 이거였던 것 같다.

매번 만들때마다 만들고 나서 아쉬움이 남았었는데,
이번에 완성한 셀렉터 엔진은 꽤나 만족스럽다.

속도도 꽤나 향상되서 다른 여타 프레임웍에 있는 셀렉터 엔진과 비견할 만큼의 퍼포먼스는 보이는 듯 하다.

아래는 내 노트북에서 Firefox2 로 속도를 비교해 본 결과. (셀렉터 5회 반복)
맨 오른쪽꺼가 이번에 만든거다.

사용자 삽입 이미지

사용자 환경이나 브라우저, 셀렉터 종류마다 차이는 있겠지만 Firefox 와 IE 에서는 다른 셀렉터 엔진이랑 비교했을때 가장 빠른 속도를 보여준다.

작년 겨울, Ajaxian 에서 DomQuery - A lightweight CSS Selector / Basic XPath implementation 포스팅을 보고 저 속도를 어찌나 동경해 왔던가.

그래서 Ext.DomQuery 랑도 1:1 로 비교해봤다. (Firefox2 - 셀렉터 50회 반복)

사용자 삽입 이미지

엎치락 뒤치락 하더니 마지막 nth-child 가상 클래스 부분에서 선전하면서 승리!
아 좋아~ (하지만 XPath 는 지원하지 않는다..)

이번에 사용상의 지원 범위로 신경 쓴건 :not 가상 클래스의 지원과 [type="val\"ue"] 형태나 :contains('I\'m a boy') 형태의 역슬래시 escape 를 사용한 표현의 지원.

추가적으로 특징적인 기능은 빈칸, >, +, ~ 연결자와 반대되는 기능의 연결자가 있다는거.
이를테면,

(Language : javascript)
  1. cssquery("input ! div"); // input 상위에 있는 div
  2. cssquery("span !> div"); // span 바로 위에 있는 div
  3. cssquery("ul !+ div"); // ul 의 바로 앞에 있는 div
  4. cssquery("p !~ div"); // p 의 앞 쪽에 있는 div

이런 식의 연결자를 (CSS 표준은 아니지만) 사용 할 수 있다.

소스 공개는 사내에서 좀 더 확인 과정을 거치고 할 듯.
영양가 있는 포스팅인가요
(총 4분이 투표해서 1.8점) 1.8점
2008/05/14 11:13 2008/05/14 11:13

자바스크립트로 개발할때도 여러가지 디버깅툴이 있지만
가장 간단하고 애용되는 디버깅툴(?)은 바로 alert 이다-_-

하지만 이 alert 을 사용해서 디버깅할때의 문제중 하나가
뭔가 루프를 잘못 돌아 무한 alert 이 뜨는 경우가 생길 수 있다는 것.

브라우저에서 무한 alert 이 떠버리면 브라우저 프로세스를 죽여버리지 않는 이상 벗어날수가 없다.

그런 상황마다 매번 브라우저 죽였다가 다시 띄우고 하는게 여간 성가신 작업이 아닌데...
그래서 만들어 봤다-_-

무한 얼럿 방지 스크립트 (Language : javascript)
  1. /**
  2. * @author http://hooriza.com/
  3. *
  4. * 무한 얼럿 방지 스크립트-_-
  5. */
  6. (function() {
  7.  
  8.   window._alert = window.alert;
  9.  
  10.   window.alert = function(s) {
  11.  
  12.     var f = arguments.callee;
  13.     if (f.ignore) return;
  14.  
  15.     f.count = (new Date().getTime() - f.last < 500) ? f.count + 1 : 0;
  16.  
  17.     if (f.count >= 10) {
  18.       if (confirm('앞으로 alert 무시?')) f.ignore = true;
  19.       f.count = 0;
  20.     }
  21.  
  22.     var r;
  23.     if (!f.ignore) r = window._alert(s);
  24.  
  25.     f.last = new Date().getTime();
  26.     return r;
  27.   };
  28.  
  29.   window.alert.count = 0;
  30.   window.alert.last = 0;
  31.  
  32. })();

사용방법은... 그냥 위의 코드만 넣어주면 된다.

0.5초 이내의 시간 간격으로 얼럿창이 10번 이상 뜨게되면 confirm 창이 하나 뜨게 되고 여기서 확인을 누르면 이후의 alert 은 모두 무시된다.

잘라고 불 끄고 누워있다가 갑자기 생각나서 일어나 만들었다.
제길;

이제 진짜로 자야지.

내용추가 :
간단하게 사용하고 싶으신 분은 아래 코드만 HTML 상단에 추가해서 쓰세요.

(Language : html4strict)
  1. <script src="http://hooriza.com/js/alert.js" type="text/javascript" language="javascript"></script>

영양가 있는 포스팅인가요
(총 2분이 투표해서 3.5점) 3.5점
2008/05/06 23:24 2008/05/06 23:24

아래 올린 타입검사 코드를 사용하여 오버로딩을 구현했다.
같은 함수명으로 여러가지 서로 다른 타입의 인자를 받아들이는 함수를 등록하면 호출 시 가장 적당한 함수를 찾아서 실행해주는 식이다.

(Language : javascript)
  1. /**
  2. * 함수 오버로딩
  3. *
  4. * @author hooriza
  5. */
  6. Function.prototype.overload = function(fpAddFunc) {
  7.  
  8.   var fpRet = this;
  9.  
  10.   // 이미 오버로드 된 함수인지
  11.   var bOverloaded = this._overloaded ? true : false;
  12.  
  13.   // 오버로드 안 되어 있으면
  14.   if (!bOverloaded) {
  15.  
  16.     fpRet = function() {
  17.  
  18.       var aLists = arguments.callee._overloaded;
  19.       var fpRaw = null;
  20.  
  21.       // 인자갯수까지 완벽히 일치하는걸로 실행
  22.       for (var i = 0, fpMethod; fpMethod = aLists[i]; i++) {
  23.  
  24.         if (fpMethod.typesMatch) {
  25.  
  26.           if (fpMethod.typesMatch(arguments, true))
  27.             return fpMethod.apply(this, arguments);
  28.  
  29.         } else if (!fpRaw) {
  30.  
  31.           fpRaw = fpMethod;
  32.  
  33.         }
  34.  
  35.       }
  36.  
  37.       // 대충 맞는 거라도 실행
  38.       for (var i = 0, fpMethod; fpMethod = aLists[i]; i++) {
  39.  
  40.         if (fpMethod.typesMatch && fpMethod.typesMatch(arguments, false))
  41.           return fpMethod.apply(this, arguments);
  42.  
  43.       }
  44.  
  45.       // 아예 types 안 정해진 함수 실행
  46.       if (fpRaw) return fpRaw.apply(this, arguments);
  47.  
  48.       // 실행 할 메쏘드 없음 예외 발생
  49.       throw new Error('Not found the matched method');
  50.      
  51.     };
  52.  
  53.     fpRet._overloaded = [ this ];
  54.  
  55.   }
  56.  
  57.   fpRet._overloaded.push(fpAddFunc);
  58.  
  59.   return fpRet;
  60.  
  61. };

사용은 아래처럼 한다.

(Language : javascript)
  1. var foo = function(nNumber) {
  2.   alert('숫자!');
  3. }.types(Number);
  4.  
  5. foo = foo.overload(function(sStr) {
  6.   alert('문자열!');
  7. }.types(String));
  8.  
  9. foo = foo.overload(function(nNumber, aArray) {
  10.   alert('숫자랑 배열!');
  11. }.types(Number, Array));
  12.  
  13. foo = foo.overload(function(oAnything) {
  14.   alert('아무거나');
  15. });
  16.  
  17. foo(10); // 결과 : 숫자!
  18. foo('hello'); // 결과 : 문자!
  19. foo(10, []); // 결과 : 숫자랑 배열!
  20. foo({}); // 결과 : 아무거나

이를 사용하면 클래스를 구현할때 메쏘드 오버로딩이 가능하도록 개발할 수 있다.
영양가 있는 포스팅인가요
(총 3분이 투표해서 2.0점) 2.0점
2008/04/08 16:20 2008/04/08 16:20

약타입 언어인 자바스크립트에서는
기본적으로 함수의 인자 타입의 검사를 하지 않는다.

하지만 함수가 아무 타입의 값을 받아들일 수 있다는 것이
아무 타입의 값을 넣어도 정상작동 한다는 의미는 아니기 때문에
간혹 타입 검사가 필요한 경우가 있다.

그 경우는 보통 아래처럼 짜기 나름.

(Language : javascript)
  1. function foo(nNumber) {
  2.   if (typeof nNumber != 'number') {
  3.     // throw new Error('숫자를 넣어주세요');
  4.     return;
  5.   }
  6.  
  7.   // ... 코드생략 ...
  8. }


이번에 짠 코드는 이런 코드타입 검사를 손쉽게 해주는 Function.prototype 의 확장기능이다.

(Language : javascript)
  1. /**
  2. * 함수 사용 타입 설정
  3. *
  4. * @author hooriza
  5. */
  6. Function.prototype.types = function() {
  7.  
  8.   var fpFunc = this;
  9.   var aTypes = arguments;
  10.  
  11.   var fpRet = function() {
  12.  
  13.     var r;
  14.  
  15.     if (!arguments.callee.typesMatch(arguments, false))
  16.       throw new Error('Illegal arguments');
  17.  
  18.     r = fpFunc.apply(this, arguments);
  19.     return r;
  20.  
  21.   };
  22.  
  23.   fpRet.typesMatch = function(aArgs, bStrict) {
  24.  
  25.     if (bStrict && aArgs.length != aTypes.length) return false;
  26.  
  27.     var oArg, oType;
  28.  
  29.     // 미리 정해진 타입의 갯수만큼 루프돌기
  30.     for (var i = 0, len = aTypes.length; i < len; i++) {
  31.  
  32.       oArg = aArgs[i];
  33.       oType = aTypes[i];
  34.  
  35.       // 정해진 타입에 따라 체크하는 방법이 다름
  36.       switch (oType) {
  37.       case String:
  38.         if (typeof oArg != 'string') return false;
  39.         break;
  40.  
  41.       case Number:
  42.         if (typeof oArg != 'number') return false;
  43.         break;
  44.  
  45.       case Object:
  46.         if (typeof oArg != 'object' && !(oArg instanceof Array)) return false;
  47.         break;
  48.  
  49.       default:
  50.         if (!(oArg instanceof oType)) return false;
  51.       }
  52.  
  53.     }
  54.  
  55.     return true;
  56.   };
  57.  
  58.   return fpRet;
  59.  
  60. };
  61.  

사용은 아래처럼 한다.

(Language : javascript)
  1. var foo = function(nNumber, sStr) {
  2.   // ...
  3. }.types(Number, String);
  4.  
  5. foo(100, 'hello'); // OK
  6. foo(100); // 예외발생
  7. foo('hello'); // 예외발생
  8. foo(100, 'hello', 'more'); // OK


뭐 이런 식.
이를 응용해서 메쏘드 오버로딩 기능을 만들 수 있다.
영양가 있는 포스팅인가요
(아무도 투표를 안 했어요) 0점
2008/04/08 16:12 2008/04/08 16:12

◀ PREV : [1] : [2] : [3] : [4] : [5] : ... [7] : NEXT ▶