ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 프록시란 무엇일까?
    Javascript 2022. 10. 3. 20:54

    Javascript에서 Proxy를 다루는 내용들이 있습니다.

    Proxy란 무엇이고 어떻게 사용해야 할까요?

    ECMAScript 6에서 정의되어진 Proxies에 대해서 알아보고 사용법을 익혀보는 시간을 가져 보시죠 : )

    프록시란 무엇일까

    MDN의 문서의 내용과 같이 프록시 객체는 다른 객체에 대한 프록시를 만들고, 이 객체는 해당 객체에 대한 기본 작업을 가로채고 재정의할 수 있는 작업들을 할 수 있다는 것입니다.

    다시말하면, 그 객체는 해당 객체를 래핑하고, 그 객체를 재정의하고 사용할 수 있는 것입니다.

    일반적으로, 이러한 작업들을 우리는 객체를 가져와서 숨겨진 게이트웨이를 생성하고 원하는 객체에 대한 모든 액세스를 제어할 수 있도록 프록시로 포장한다는 것을 의미합니다.

     

    프록시는 두개의 파라미터로 만들어집니다.

    • target : 감싸고 싶은 원본 객체
    • handler : 가로채는 작업을 재정의하는 방법을 정의하는 메서드
    const target = {
      name: "noel",
      region: "incheon"
    };
    
    const handler = {};
    
    const proxy = new Proxy(target, handler);

    프록시는 대부분의 브라우저에서 지원되고, 지원하지 않는 오래된 브라우저들은 폴리필로 대체 가능합니다.

    프록시 사용법

    만약에 A 편의점에 포켓몬 빵의 재고가 변경될 때마다 알림을 받고 싶습니다.

    그러면 프록시를 사용해서 어떻게 할 수 있을까요?

    const convenientStore = {
      count: 10,
      name: '포켓몬 빵'
    };
    
    const handler = {
       get: function(target, prop, receiver) {
        if (prop === 'count') {
    	console.log(`현재 ${target.name}의 개수 : ${target.count} 개`);
        }
        return target[prop];
      }
    };
    
    const wrappedConvenientStore = new Proxy(convenientStore, handler);
    wrappedConvenientStore.count;
    
    // 결과
    // 현재 포켓몬 빵의 개수 : 10 개
    // 10

    위의 예시로부터 우리는 handler를 통해서 포켓몬 빵의 count에 접근했을 때 현재 포켓몬 빵의 개수가 10개라는 것을 알 수 있었습니다.

     

    다음 예시는 3개의 파라미터를 받습니다.

    우리는 위의 A 편의점에서 누군가가 포켓몬 빵을 사갔을 때 알림을 받기를 원합니다. 

    그리고 또 다른 제약사항으로 편의점은 포켓몬 빵이 0개 미만으로는 내려갈 수 없다는 것 입니다.

    이를 위해서 handler/trap을 사용하겠습니다.

     

    const convenientStore = {
      count: 10,
      name: '포켓몬 빵'
    };
    
    const handler = {
       set: function(obj, prop, value) {
       console.log(`현재 ${obj.name}의 개수 : ${obj.count} 개`);
       if (value < 0) {
           console.log(`포켓몬 빵은 0개 미만이 될 수 없습니다`);
           return false;
       }
       obj[prop] = value;
       return true;
      }
    };
    
    const wrappedConvenientStore = new Proxy(convenientStore, handler);
    
    wrappedConvenientStore.count -= 5;
    console.log(wrappedConvenientStore.count);
    
    wrappedConvenientStore.count -= 25;
    console.log(wrappedConvenientStore.count);
    
    // 현재 포켓몬 빵의 개수 : 10 개
    // 5
    // 현재 포켓몬 빵의 개수 : 5 개
    // 포켓몬 빵은 0개 미만이 될 수 없습니다
    // 5

    위와 같이 더 이상 감소할 수 없다면 return false를 통해서 작업을 중단할 수 있습니다.

    프록시를 사용하고 있는 기술들

    많은 기술들이 Proxies를 사용하고 있습니다.

    Mobx라던지, Vue, Immer와 같은 상태관리 라이브러리 등이 사용중입니다.

    변화가 감지되어 반영되게 만들어야하는 양방향 바인딩을 위한 상태 감지 등 가로채고 재정의하는 모든 메서드에서 사용됩니다.

    예시

    위에서 사용했듯이 로그로도 사용할 수 있고, 유효성 검사로도 작용할 수 있을 것 같네요.

    캐싱적용

    캐싱 적용을 해봅니다.

    const convenientStore = {
      count: 10,
      name: '포켓몬 빵',
      get price() {
          console.log('빵의 가격');
          return this.count * 1000;
      }
    };
    
    let cache = {
        currentCount: null,
        currentValue: null
    }
    
    const handler = {
        get: function(obj, prop) {
            if (prop === 'price') {
                let value = cache.currentCount !== obj.count ? obj[prop] : cache.currentValue;
                cache.currentValue = value;
                cache.currentCount = obj.count;        
                return value;
            }
            return obj[prop];
        }
    };
    
    const wrappedConvenientStore = new Proxy(convenientStore, handler);
    
    console.log(wrappedConvenientStore.price);
    console.log(wrappedConvenientStore.price);
    console.log(wrappedConvenientStore.price);
    console.log(wrappedConvenientStore.price);
    
    // 빵의 가격
    // 10000
    // 10000
    // 10000
    // 10000

    DOM 조작

    상태가 변경될 때마다 화면의 값들을 업데이트 하고 싶습니다.

    set operator/trap을 사용해서 해봅니다.

    const convenientStore = {
      count: 10,
      name: '포켓몬 빵',
      get text() {
          return `${this.name}의 개수는 ${this.count}개 입니다.`;
      }
    };
    
    const domManipulate = (object, domId) => {
        const handler = {
            set: function(obj, prop, value) {
                obj[prop] = value;
                document.getElementById(domId).innerHTML = obj.text;
                return true;
            }
        };
        return new Proxy(object, handler);
    }
    
    const wrappedConvenientStore = domManipulate(convenientStore, "domId");
    
    wrappedConvenientStore.count = 300;
    wrappedConvenientStore.count = 500;

    See the Pen Proxy by YoungMinKim (@oinochoe) on CodePen.

    Proxy에 대해서 알아가는 시간이 되셨기를 바랍니다 : )

     

     

    출처 : https://levelup.gitconnected.com/the-amazing-power-of-javascript-proxies-aa27c6d06bcb

Designed by Tistory.