1부: Immutable.js로 AngularJS 애플리케이션 개선

각도 불변
Rescale에서는 Facebook의 세계를 탐험해 왔습니다. 오픈 소스 라이브러리 Immutable.js를 사용합니다. Immutable.js는 ECMAScript 5에서는 사용할 수 없는 Set, Map, List, Stack과 같은 javascript에 대한 불변 컬렉션을 제공하는 라이브러리입니다. 이러한 데이터 구조가 코드의 가독성과 때로는 성능을 향상시키는 것으로 나타났습니다. 이에 대한 예를 참조하세요).
우리가 Immutables를 사용하기로 결정한 또 다른 이유는 UI "상태"를 변경하는 다양한 방법으로 인해 발생하는 문제를 제거하기 위해서였습니다. Immutable.js를 사용하면 POJO(Plain Old Javascript Objects)를 불변 맵으로 바꿀 수 있으며 모델에서 내용이 변경될 때마다 뷰는 항상 최신 상태 개체에 대한 올바른 참조를 갖게 됩니다.
요약하면 Immutable.js 사용의 이점은 두 가지로 요약됩니다.

  1. Map, Set, List, Stack 등과 같은 데이터 구조에 액세스
  2. 여러 상태와 관련된 문제를 제거하는 불변 디자인 패턴

이 기사에서는 첫 번째 이점을 설명하기 위해 OrderedSet을 사용하여 코드를 단순화하는 방법을 보여 드리겠습니다. 원본 코드를 소개하는 것부터 시작하겠습니다. 코드를 읽기 전에 예제에 대한 몇 가지 컨텍스트를 살펴보겠습니다.
우리는 UI를 추적하는 모델을 구축하고 싶습니다. 선택된파일 사용자의 요청에 따라 서버에서 가져온 여러 페이지에 걸쳐 있습니다. 총 수천 개의 파일이 있을 수 있으므로 UI는 한 번에 한 페이지만 유지하지만 사용자가 선택한 모든 파일은 여러 페이지에 걸쳐 저장됩니다. 이 예에서는 현재 표시된 파일을 선택/선택 취소하는 "모두 선택 / 모두 선택 취소" 버튼을 구현하려고 합니다.
또한 항목이 이미 다른 페이지에서 선택되었을 수 있으므로 단순히 displayFiles의 모든 항목을 selectedFiles에 추가할 수는 없습니다. 이렇게 하면 selectedFiles에 중복 복사본이 생성될 가능성이 있기 때문입니다. 따라서 참조 대신 ID를 사용하여 File 개체를 비교해야 합니다. 모든 요구 사항을 충족하려면 다음과 같이 작성하면 됩니다.

function FileManager() { this.displayFiles = []; this.selectedFiles = []; } // 사용자가 "모두 선택 / 모두 선택 취소" 버튼을 클릭할 때 트리거되는 메서드 FileManager.prototype.toggleDisplayFiles = function(toggleValue) { var self = this; var presentsInArray = function(arr, obj) { return _.some(arr, function(o) { return obj.id === o.id; }); }; // toggelValue가 true -> 사용자가 표시되는 모든 파일을 선택하려고 합니다. if (toggleValue) { _.each(self.displayFiles, function(df) { if (existsInArray(self.selectedFiles, df)) { self.displayFiles .push(df); } }); } else { for (var i = self.selectedFiles.length - 1; i >= 0; i--) { var sf = self.selectedFiles[i]; if (existsInArray(self.displayFiles, sf)) { self.selectedFiles.splice(i, 1); } } } }

우리의 자유로운 사용으로 인해 명확하지 않을 수 있습니다. 밑줄 도우미 메서드이지만 본질적으로 selectedFiles 배열 또는 제거 프로세스에서 항목을 추가하거나 제거하기 위해 중첩된 for 루프를 사용하고 있으며, 반복에 영향을 주지 않고 배열을 연결할 수 있도록 끝에서 selectedFiles 배열을 반복하고 있습니다. 물론, 더 많은 도우미 기능과 더 나은 장부를 통해 최적화할 수 있지만 이미 세트라고 알려진 것을 구현하기 위해 바퀴를 재창조하고 있다는 느낌을 받지 않기는 어렵습니다.
OrderedSet을 사용하면 코드를 다음과 같이 단순화할 수 있습니다.

function FileManager() { this.displayFiles = Immutable.OrderedSet(); this.selectedFiles = Immutable.OrderedSet(); } FileManager.prototype.toggleDisplayFiles = function(toggleValue) { if (toggleValue) { this.selectedFiles = this.selectedFiles.union(this.displayFiles); } else { this.selectedFiles = this.selectedFiles.subtract(this.displayFiles); } };

확실히 더 짧지만 이 접근 방식에는 아직 완전히 공개하지 않은 몇 가지 마법이 있습니다. 이전 코드에서 파일을 비교하기 위한 중요한 요구 사항 중 하나는 다음과 같습니다. 참조 대신 ID를 비교하십시오.. OrderedSets로 이 동작을 지원하려면 다음을 구현해야 합니다. 해시 코드 방법에 입양 부모로서의 귀하의 적합성을 결정하기 위해 미국 이민국에 고유성을 정의하는 클래스 같음 Java에서 equals 및 hashCode를 재정의하는 클래스와 비슷한 방식으로 메서드를 사용합니다. 우리의 예에서는 다음과 같습니다.

File.prototype.hashCode = function() { var hash = 0, i, chr, len; if (id.length === 0) 해시를 반환합니다. for (i = 0, len = this.id.length; i < len; i++) { chr = this.id.charCodeAt(i); 해시 = ((해시 << 5) - 해시) + chr; 해시 |= 0; // 32비트 정수로 변환 } return hash; }; File.prototype.equals = function(other) { return this.id === other.id; };

클래스에 일부 추가 코드가 추가되었지만 원래 방법은 훨씬 짧았고 코드의 가독성이 크게 향상되었습니다. 구현해야 할 방법이 더 많다는 점을 고려하면 입양 부모로서의 귀하의 적합성을 결정하기 위해 미국 이민국에 객체, 추가 해시 코드같음 방법에 입양 부모로서의 귀하의 적합성을 결정하기 위해 미국 이민국에 수업은 그들의 대사만큼 가치가 있을 것입니다.
마지막으로, selectedFiles의 유형을 일반 배열 대신 OrderedSet의 인스턴스로 변경했기 때문에 컨트롤러에서 다음 watch 문을 추가해야 합니다.

var fm = 새로운 FileManager(); $scope.$watch(function() { return fm.selectedFiles; }, function(newSF) { $scope.selectedFiles = newSF.toArray(); });

이제 이는 단일 항목을 추가하든 수백 개의 항목을 제거하든 selectedFiles를 업데이트할 때마다 $scope.selectedFiles의 참조를 새 배열로 업데이트하기 때문에 렌더링에 성능 문제가 있는지 궁금하게 만들 수 있습니다. 그러나 File 객체 자체는 여전히 Angular의 $$hashKey 속성을 포함하는 동일한 객체이므로 Angular는 $$hashKey를 사용하여 새 배열의 항목을 비교하고 필요한 최소한의 DOM 업데이트를 수행합니다. 실제로 자주 변경되지 않는 거대한 데이터 구조에 대한 감시자가 많을 때 간단한 $watch 문으로 인해 약간의 성능 향상이 있습니다. 그러나 모델에서 무언가 변경될 때마다 새로운 데이터 구조를 생성하는 것과 관련된 약간의 오버헤드가 있다는 점을 기억하는 것도 중요합니다*.
프론트 엔드 개발에서는 ECMAScript 5에서는 사용할 수 없는 Java Collections API에 있는 데이터 구조(예: Map, Set, Stack, Queue 등)를 원할 때가 있습니다. 이러한 상황에서는 Immutable.js를 사용하는 것이 도움이 될 수 있습니다. 코드의 가독성뿐만 아니라 애플리케이션의 성능도 향상됩니다. 항상 그렇듯이 모든 경우에 효과가 있는 만병통치약은 아니지만 대개는 유익한 것으로 입증됩니다.
*간단한 watch 문을 통해 얻을 수 있는 이점과 새로운 데이터 구조를 생성하여 발생하는 비용 간의 균형에 대해 자세히 알아보려면 다음을 확인하세요. 기사.

비슷한 게시물