ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Angular.js 의 작동원리
    Javascript 2016. 6. 27. 23:13



    Angular.js 는 MVC 아키텍처로 단일 페이지 어플리케이션(SPA) 를 구축하기 위해 설계된 프론트엔드 Javascript 


    Framework 이다. Angular.js 의 가장 큰 특징은 클라이언트 쪽 템플릿과 모델과 뷰 사이의 빈틈없는 동기화를 


    위한 양방향 데이터 결합 이다. 또한 Angular.js 는 MVC 와 의존성 주입을 사용해 애플리케이션 코드 구조와 


    테스트성을 개선한다. 


    모든 angular.js 애플리케이션은 최소한 한개의 모듈이 필요하며 , 이 모듈을 애플리케이션 모듈이라고 지칭한다.


    angular.js 모듈은 angular.module(name, [requires], [configFN]) 메소드를 사용해 생성하고 인출 할 수 있다.


    이 3개의 인수에 대해서 말하자면


    name : 모듈 이름을 정의하는 문자열


    requires : 의존성으로 다른 모듈을 정의하는 문자열 배열


    configFN : 모듈이 등록될 때 수행될 함수  


    의 역활을 한다. 


    단일 인수로 angular.module() 메소드를 호출 할 때는 해당 이름을 사용햐 기존 모듈을 인출할 것 이다. 


    여러 인수로 angular.module() 메소드를 호출할 때는 넘긴 이름, 의존성, 구성 함수로 모듈을 생성할 것 이다. 




    - 양방향 데이터 결합



    angular.js 의 가장 큰 특징인 양방향 데이터 결합을 할아보자 .


    양방향 데이터 결합은 항상 Angular.js 애플리케이션이 모델을 뷰와 동기화한 상태로 유지하거나 반대로 뷰를 


    모델과 동기화한 상태로 유지하게 만들어준다.  이는 뷰 츌력이 항상 모델을 반영함을 의미한다. 






    위 그림과 같은 기존의 대다수 템플릿 시스템은 템플릿을 사용해 일방향으로 모델을 결합한다.  따라서 모델이 


    변경될 때 마다, 개발자는 이런 변경내용이 뷰에 반영되리라는 사실을 확실 할 수 있다. Meanstack 에서 썼던 EJS


    템플릿이 이런 형식이다. 모델의 데이터와 템플릿을 합쳐서 HTML 페이지를 만들어 사용자에게 보여주고 있다. 



    하지만 angular.js 는 동작방식이 다르다. 




    angular.js 는 HTML 템플릿을 컴파일하기 위해 브라우저를 사용한다. HTML 템플릿은 실시간 뷰를 생성하기 위한 


    결합 명령과 특수 지시자를 포함한다. 뷰에서 발생하는 어떤 이벤트도 자동으로 모델을 갱신하고, 모델에서 


    발생하는 변경은 즉시 뷰로 전파된다.  이는 모델이 항상 애플리케이션 상태를 알려주는 단일 데이터 출처임을 


    의미하며, 개발 과정을 상당히 높은 수준까지 개선할 수 있으며, 이는 SPA (Single Page application) 에 아주 


    어울리는 동작 방식이라고 볼 수 있다. 






    -의존성 주입

     

    의존성 주입은 마틴 파울러가 대중화한 소프트웨어 디자인 패턴이다. 소프트웨어 개발 아키텍처에서 의존성 주입 


    이면의 핵심원리는 제어 역전 이다.  이를 이해하기 위해 다음 코드를 보자. 



    var Notifier = function() {
        this.userService = new UserService();
    };
    Notifier.prototype.notify = function() {
        var user = this.userService.getUser();
    
        if(user.role === 'admin') {
            alert('You are an admin');
        } else {
            alert('Hello user');
        }
    }
    
    
    



    이 코드를 보면 Notifier 라는 알림 클래스를 생성하였고 이는 userService 의 인스턴스를 생성한다. 


    그리고 Notifier 에 notify() 라는 메소드를 정의하였고 이 메소드는 생성된 userService의 getUser() 메소드를 


    사용하여 유저의 정보를 얻어온다.  (getUser() 메소드는 유저의 정보를 가져오는 메소드라고 임의로 생각하자.)


    그리고 가지고 온 user 의 정보를 바탕으로 admin 과 일반 유저에게 다른 메시지를 전달 할 것 이다. 


    이는 제대로 된 코드이고 잘 작동할 것 이다.  하지만 여기서 notify() 메소드를 테스트 하고 싶다면 어떻게 해야 


    할까?  notify() 메소드의 결과 테스트를 위해 가짜 userService 객체를 전달 할 수도 없다. 



    의존성 주입은 이 userService 의 객체 생성 주체를 Notifier 가 아닌 Notifier 인스턴스를 생성하는 주체로 옮김


    으로써 이를 해결한다.  한마디로 Notifier 클래스를 사용하는 곳에서 userService 의 객체를 주입할 수 있게 해서


    Notifier 의 제어를 외부에서 컨트롤 할 수 있도록 하는 것 이다.



    수정된 코드를 보면 바로 이해가 될 것 이다.



    var Notifier = function(userService) {
        this.userService = userService;
    };
    Notifier.prototype.notify = function() {
        var user = this.userService.getUser();
    
        if(user.role === 'admin') {
            alert('You are an admin');
        } else {
            alert('Hello user');
        }
    }
    
    
    


    무엇이 바뀌었는지 보이는가? 단순히 Notifer 클래스에 userService 인수를 받게 하였다. 


    이렇게 함으로서 Notifier 클래스의 인스턴스를 생성할 때 마다, 주입자는 userService 객체를 생성 주체 (Notifier)


    에 주입하는 책임을 맡기에, 생성 주체 외부에서 Notifier 의 동작방식을 제어하게 된다. 이런 설계방식이 제어역전


    으로 기술된다. 




    의존성 주입에 대하여 어느정도 이해를 했다면 angular.js가 사용하는 방식을 제대로 이해하기 위해 


    angular.js 의 컨트롤러 메소드를 생성하는 controller() 메소드 예제를 보자. 



    angular.module('someModule').controller('SomeController', function($scope) {
         ......
    });
    



    위 예제를 보면 controller 메소드는 컨트롤러 이름과 컨트롤러의 생성자 함수를 인수로 받아들인다. 


    컨트롤러의 생성자 함수는 $scope 라는 angular.js 객체와 함께 주입된다. 


    angular.js 가 여기서 올바른 객체를 주입하는 방법을 아는 이유는 injector 객체가 함수 인수 이름을 읽을 수 


    있기 때문이다.  하지만 여기서 배포를 위해 자바스크립트 파일을 난독화하며 크기를 줄이기 위해 최소화 서비스를


    사용한다.  (보통 js 라이브러리 뒤에 .min 이라고 붙은 파일들이 최소화 시킨 파일들이다.)


    자바스크립트 파일을 최소화 시킬때 인수나 변수의 이름이 최소화로 줄어드는 경우가 있는데 , 이렇게 되면 


    위 angular controller() 메소드는 아래와 같이 변할 것 이다. 


    angular.module('someModule').controller('SomeController', function(a) 
    { ......});
    



    위 처럼 $scope 라는 인수가 a 로변경되면 angular.js 주입자가 어떤 객체를 주입해야 하는지 이해 할 수 없다. 


    이런 문제를 풀기 위해 angular.js 에서는 메소드에 함수를 둘째 인수로 전달하는 대신 최소화 할 때 변경되지 않는


    어노테이션이 달린 의존성 배열을 전달할 수 있다. 


    angular.module('someModule').controller('SomeController', ['$scope', 
    function($scope) { 
    ......
    }]);
    


    위 코드처럼 $scope 라는 어노테이션을 포함한 배열을 인수로 주어 코드를 난독화하고, 최소화 하여도 의존성


    목록은 바뀌지 않은 상태로 남아있기에 정상적으로 작동할 것 이다. 


    에제로 controller() 메소드를 사용했지만 다른 angular.js 엔티티에도 유효하다.




    - Angular.js 지시자 


    위에서 angular.js 는 HTML을 확장한다고 설명했는데, 이를 가능하게 만드는 메커니즘을 지시자 라고 한다.


    angular.js 지시자는 일반적으로 표식이며, 속성이나 엘리먼트 이름이다. 기본적으로 지시자는 angular.js가 


    DOM 엘리먼트 들과 상호 작용하는 수단이며, angular.js 애플리케이션의 기본적인 연산을 가능하게 만드는


    수단이다.  이런 지시자의 기능을 더욱 특수하게 만들기 위해 독자적인 맞춤식 지시자를 작설할 수 도 있다.



    angular.js 의 핵심지시자는 ng-app 이다. 


    이는 루트 애플리케이션 엘리먼트로 angular.js 를 사용하기를 원하는 DOM 엘리먼트에 위치한다. 


    기본적으로 body 태그에 붙이고 사용한다. 


    <body ng-app></body>


    그외 핵심지시자들을 보면


    ng-controller : 컴파일러에게 이 엘리먼트 뷰를 관리하기 위해 어떤 컨트롤러 클래스를 사용할지 알려준다.


    ng-model : input 엘리먼트에 위치하며 , input 값을 모델의 속성에 결합한다. 


    ng-show/ng-hide : bool 표현식에 따라 엘리먼트를 노출하거나 감춘다.


    ng-repeat : 컬렉션을 순회하고 개별 아이템마다 엘리먼트를 중첩한다. 



    그외 수많은 angular.js 의 지시자와 기능을 다 열거하기에는 그 양이 너무 방대하다. 


    본 블로그 meanstack 카테고리 16장부터 angular.js 를 사용할 것 이고 


    angular.js 의 나머지 부분은 meanstack 으로 web application 을 만들면서 필요할 때 마다 설명을 하겠다. 



    ( angular.js2역시 현재 나왔지만   , angular.js2는 angular.js 와 비해 많은 부분이  바뀌었다.  


    기본적으로 Typescript 를 베이스로 사용하기에 angular.js 2 는 따로 다루도록 하겠다. )





    (끝) 






    댓글