본문 바로가기
Study Note/Javascript

javascript #디자인패턴 - Init-time branching 패턴

by 시뮝 2021. 2. 10.
728x90

Init-time branching 패턴

Init-time branching 패턴은 이름 그대로 초기화 단계에서 분기하여 같은 함수를 환경에 따라 다르게 정의하는 것을 의미합니다. 보통 웹페이지가 처음 열릴 때 실행된다고 해서 Init-branching 패턴이라고도 하며, 페이지가 로드될 때 실행되기 때문에 Load-branching 패턴이라고도 합니다. 브라우저 호환성을 보장해줄 때 사용하면 좋은 패턴입니다.

 

적용예시1. 이벤트 핸들러 호환성 지원

1. navigator.appName 으로 호환성 지원

과거에는 이렇게 처리하는 웹페이지들이 많았으나, 최근에는 이렇나 처리 방식이 적당하지 않습니다. 웹페이지들이 Internet Explorer8을 구분하기 위해 위의 소스를 이용하는 이유는 이벤트 핸들러 설정 때문입니다. 구버전 브라우저를 생각해서 이벤트 핸들러의 호환성을 지원해주는 것이죠.

<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        <script type="application/javascript">
        (function(){
            let IEVersion = getIEVersion();
            
            if (IEVersion === -1) {
                console.log("Not IE");
            } else if (IEVersion < 9) {
                console.log("IE 8 or lower, need to upgrade");
            } else {
                console.log("IE 9 or higher");
            }
            function getIEVersion() {
                // navigator.userAgent 중간의 MSIE 8.0 숫자를 가져오기 위한 정규 표현식
                if (navigator.appName == "Microsoft Internet Explorer" && /MSIE ([0-9]{1,}[\.0-9]{0,})/.exec(navigator.userAgent) != null) {
                    return parseFloat(RegExp.$1);
                } else {
                    return -1;
                }
            }
        }());
        </script>
    </body>
</html>

 

2. IE 9 버전보다 낮은 버전이면 attachEvent() 함수 적용

IE 버전에 맞춰 attachEvent() 함수를 적용하는 예시입니다. 다른 브라우저 버전을 확인할 수 없는 단점이 있습니다. 더 바람직한 방법은 3번과 같이 기능이 있는지 없는지 여부에 따라 처리하는 것입니다.

<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        <script type="application/javascript">
        (function(){
            function getInternetExplorerVersion() {
                let rv = -1;
                if (navigator.appName == 'Microsoft Internet Explorer') {
                    let ua = navigator.userAgent;
                    let re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
                    if (/"MSIE ([0-9]{1,}[\.0-9]{0,})"/.exec(ua) != null) {
                        rv = parseFloat( RegExp.$1 );
                    }
                }
                return rv;
            }
            
            let ieVersion = getInternetExplorerVersion(),
                addEventHandler,
                removeEventhandler;
            
            // IE 9 버전보다 낮은 버전이면 attachEvent() 함수를 사용하고,
            // 아니면 W3C 표준대로 addEventListener() 함수를 사용한다.
            if (ieVersion !== -1 && ieVersion < 9) {
                addEventHandler = function (dom, type, fn) {
                    dom.attachEvent( 'on'+type, function () {
                        fn.call(dom, window.event);
                    });
                }
                removeEventHandler = function (dom, type, fn) {
                    dom.detachEvent('on'+type, fn);
                }
            } else {
                addEventHandler = function (dom, type, fn) {
                    dom.addEventListener(type, fn);
                };
                removeEventHandler = function (dom, type, fn) {
                    dom.removeEventListener(type, fn);
                }
            }
        }());
        </script>
    </body>
</html>

 

3. addEventListener() 함수 여부에 따라 처리

IE버전을 가져오지 않고 addEventListener() 함수 여부에 따라 처리하는 방식입니다. 기능여부를 판단하여 적용하기 때문에 1번, 2번 보다 바람직합니다.

<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        <script type="application/javascript">
        (function(){
            let addEventHandler,
                removeEventhandler;
            if (document.addEventListener) {
                addEventHandler = function (dom, type, fn) {
                    dom.addEventListener(type, fn);
                }
                removeEventHandler = function (dom, type, fn) {
                    dom.removeEventListener(type, fn);
                }
            } else if (document.attachEvent) {
                addEventHandler = function (dom, type, fn) {
                    dom.attachEvent('on'+type, function () {
                        fn.callj(dom, window.event);
                    });
                }
                removeEventHandler = function (dom, type, fn) {
                    dom.detachEvent('on'+type, fn);
                };
            } else {
                addEventHandler = function (dom, type, fn) {
                    dom["on" + type] = fn;
                };
                removeEventHandler = function (dom, type, fn) {
                    dom["on" + type] = null;
                }
            }
        }());
        </script>
    </body>
</html>

 

 

적용예시2. XMLHttpRequest 객체 호환성 지원

1. 실시간 XMLHttpRequest 호환성 지원 방법

XMLHttpRequest 객체는 현재 대부분 브라우저에서 지원하나 IE 낮은 버전에서는 사용할 수 없어 이를 위한 호환성 설정이 필요합니다. 이를 위해 기존에는 XMLHttpRequest 객체를 생성하는 함수를 따로 만들어 두고 사용했었다고 합니다.

<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        <script type="application/javascript">
        function getXHR() {
            if (window.XMLHttpRequest) {
                return new XMLHttpRequest();
            }
            try {
                return new ActiveXObject("MSXML2.XMLHTTP.6.0");
            } catch (e) {
                try {
                    return new ActiveXObject("MSXML2.XMLHTTP.3.0");
                } catch (e) {
                    console.log("This browser does not support XMLHttpRequest");
                    return null;
                }
            }
        }
        </script>
    </body>
</html>

 

2. Init-time branching을 통한 getXHR() 함수 정의

 1번 예에서는 getXHR() 함수가 호출될 때마다 객체를 어떠한 방법으로 생성해야 하는지 확인해야 했지만, Init-time branching 패턴을 이용한 이번 예에서는 초기화 단계에서 최초 한 번만 분기하여 확인합니다.

 그러나 이렇게 구현하면 최초 웹페이지가 초기화될 때 객체를 초기화하고 에러가 발생할 가능성이 있어 컴퓨팅 자원소모가 일어날 수 있습니다. XMLHttpRequest 객체의 호출 빈도나 호출 시점을 잘 고려해서 Init-time branching 패턴을 적용하면 좋습니다.

<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        <script type="application/javascript">
        let getXHR = (function () {
            let xhr;
            if (window.XMLHttpRequest) {
                return function () {
                    return new XMLHttpRequest();
                }
            }
            try {
                xhr = new ActiveXObject("MSXML2.XMLHTTP.6.0");
                return function () {
                    return new ActiveXObject("MSXML2.XMLHTTP.6.0");
                }
            } catch (e) {
                try {
                    xhr = new ActiveXObject("MSXML2.XMLHTTP.3.0");
                    return function () {
                        return new ActiveXObject("MSXML2.XMLHTTP.3.0");
                    }
                } catch (e) {
                    console.log("This browser does not support XMLHttpRequest");
                }
            }
        })
        </script>
    </body>
</html>

 

이전글

2021/02/10 - [Study Note/Javascript] - javascript #디자인패턴 - 객체 기반 데커레이터 패턴

 

javascript #디자인패턴 - 객체 기반 데커레이터 패턴

하나의 객체에 여러 가지 기능들을 추가함으로써 기존의 객체에 추가로 꾸며진 객체를 만들어낼 수 있습니다. 데커레이터 패턴을 이용해 각기 다른 부품으로 이루어진 컴퓨터의 가격을 알아봅

simuing.tistory.com

2021/02/10 - [Study Note/Javascript] - javascript #디자인패턴 - 폼 검증을 위한 데커레이터 패턴

 

javascript #폼 검증을 위한 데커레이터 패턴 적용

데커레이터 패턴 프락시 패턴은 호출되는 객체가 아닌 별도의 중간자 역할을 수행하는 프락시 객체가 추가 기능을 수행하는 패턴이라고 한다면, 데커레이터(decorator) 패턴은 호출 대상이 되는

simuing.tistory.com

 

 

#

참고도서 : 속깊은 자바스크립트

참고문서 : stackoverflow.com/questions/14573881/why-does-javascript-navigator-appname-return-netscape-for-safari-firefox-and-ch

728x90

댓글