2007년 8월 28일 화요일

Lazy Function Definition Pattern

Peter Michaux님의 Lazy Function Definition Pattern

1. Lazy Function Definition Pattern이 필요한 경우

  1. 특정 값을 계산(또는 실행)을 통해서 얻어와야 하는 경우
  2. 한 번만 계산(또는 실행)이 되면 그 다음부터는 계산이 필요 없는 경우
  3. 호출 전까지는 계산(또는 실행)이 될 필요가 없는 경우
복잡하게 적어놨습니만, 그런 경우 있지 않은가요? 특정 케이스에만 사용되는 값인데 연산한번만 이루어지고 난 뒤라면 다음부터 연산할 필요가 없는 값들.... 예를 찾기 힘들군요 ^^;;

Peter님의 예를 보면 Date()를 호출하는 것을 들었습니다.
var t;  //global 변수 t를 선언합니다.

function foo() {
    if (t) {
        return t;   // t의 값이 있는 경우에는 t를 리턴합니다.
    }
    t = new Date();
    return t;      // t가 없는 경우에는 t의 new Date()를
                        // 호출하여 값을 생성한 후 리턴합니다.

}
이 방법으로 쉽게 해결할 수 있지만, 다음과 같은 문제가 존재합니다.
  1. foo가 호출될 때마다 if (t)가 호출되어 t에 값이 있는 지 여부를 체크하게 됩니다. (한 번만 체크하면 되는 부분이죠)
  2. 변수 t가 global로 선언되게 되므로, 불필요한 global 변수가 추가됩니다.

2. Lazy Function Definition Pattern으로 수정하면...
Lazy Function Definition Pattern으로 수정하게 되면 다음과 같은 코드 형태가 됩니다.

var foo = function() {
    // foo가 호출될  때 Date를 생성해서 t에 넣습니다.
    var t = new Date();
    // foo를 closure를 통하여 얻을 수 있는 값 t를 리턴하는 function으로 재정의합니다.
    foo = function() {
        return t;  
    }
    // foo()가 최초로 실행되도록 호출합니다.
    return foo();
}
foo의 변화를 alert()을 사용하여 찍어보면 다음과 같습니다.
사용자 삽입 이미지

foo()가 호출되지 않았을 때는 전체 코드를 갖고 있지만,
사용자 삽입 이미지

호출된 후에는 계산된 변수 t의 값만을 갖고 있기 때문에, global 문제와 foo() 호출 시 발생하는 if()코드도 모두 제거할 수 있습니다.

3. 문제점.
var foo = function() {
   // foo가 호출될  때 Date를 생성해서 t에 넣습니다.
    var t = new Date();
    var a, b, c, d, e;
    // a,b,c,d,e가 선언되어서 여기에서 사용되는 경우

   // foo를 closure를 통하여 얻을 수 있는 값 t를 리턴하는 function으로 재정의합니다.
    foo = function() {
        return t;  
    }
   // foo()가 최초로 실행되도록 호출합니다.
    return foo();
}
IE에서 위의 코드처럼 a,b,c,d,e가 선언되어 사용된다면, clouser를 사용해서 foo에서 접근할 수 있기 때문에 메모리에서 릴리즈되지 않습니다. 따라서, Memory leak현상이 날 수도 있습니다.

이를 해결하기 위해서는 clouser로 접근할 수 있는 모든 객체에 대해서 (여기서는 a,b,c,d,e) null처리를 해줘야지만 됩니다.

출처: Lazy Function Definition Pattern via Ajaxian

※ 1의 문제를 해결하기 위한 여러가지 방법이 Lazy Function Definition Pattern에 나와 있으니 한번 읽어보세요.

댓글 없음:

댓글 쓰기