각도 변경 감지 및 OnPush 전략

게시 됨: 2022-03-11

좋아하는 모든 프로젝트에 Angular를 사용하기 시작했습니다. Angular가 무엇을 제공하는지, 그리고 이를 어떻게 활용하여 놀라운 웹 앱을 구축할 수 있는지 알고 있습니다. 그러나 Angular에는 몇 가지 사항이 있으며 이를 알면 프로젝트에 Angular를 더 잘 사용할 수 있습니다.

Angular의 거의 모든 것의 중심에 데이터 흐름이 있으므로 변경 감지는 버그를 훨씬 더 쉽게 추적하고 복잡한 데이터 세트로 작업할 때 앱을 더욱 최적화할 수 있는 기회를 제공하므로 알아야 할 가치가 있습니다.

각도 변경 감지 및 OnPush 전략

이 기사에서는 Angular가 데이터 구조의 변경을 감지하는 방법과 Angular의 변경 감지 전략을 최대한 활용하기 위해 변경할 수 없도록 만드는 방법을 배웁니다.

Angular의 변화 감지

모델을 변경하면 Angular가 변경 사항을 감지하고 즉시 보기를 업데이트합니다. 이것은 Angular의 변경 감지입니다. 이 메커니즘의 목적은 기본 보기가 항상 해당 모델과 동기화되도록 하는 것입니다. Angular의 이 핵심 기능은 프레임워크를 작동하게 하고 부분적으로 Angular가 최신 웹 앱 개발에 적합한 선택인 이유입니다.

Angular의 모델은 다음 시나리오의 결과로 변경될 수 있습니다.

  • DOM 이벤트(클릭, 마우스 오버 등)

  • AJAX 요청

  • 타이머(setTimer(), setInterval())

변화 감지기

모든 Angular 앱은 계층적 구성 요소 트리로 구성됩니다. 런타임에 Angular는 트리의 모든 구성 요소에 대해 별도의 변경 감지기 클래스를 생성한 다음 결국 구성 요소의 계층 구조 트리와 유사한 변경 감지기의 계층을 형성합니다.

변경 감지가 트리거될 때마다 Angular는 이 변경 감지기 트리를 따라 이동하여 변경 사항을 보고한 항목이 있는지 확인합니다.

변경 감지 주기는 감지된 모든 변경에 대해 항상 한 번 수행되며 루트 변경 감지기에서 시작하여 순차적인 방식으로 계속 진행됩니다. 이 순차 설계 선택은 구성 요소 데이터가 상위에서만 올 수 있다는 것을 알고 있기 때문에 예측 가능한 방식으로 모델을 업데이트하기 때문에 좋습니다.

변경 감지기 계층

변경 감지기는 Angular에 변경 사항을 보고하기 위해 구성 요소의 이전 및 현재 상태와 구조를 추적하는 방법을 제공합니다.

Angular가 변경 감지기에서 보고서를 받으면 해당 구성 요소에 DOM을 다시 렌더링하고 그에 따라 업데이트하도록 지시합니다.

변화 감지 전략

값 대 참조 유형

변경 감지 전략이 무엇이며 작동하는 이유를 이해하려면 먼저 JavaScript에서 값 유형과 참조 유형의 차이점을 이해해야 합니다. 이것이 어떻게 작동하는지 이미 알고 있다면 이 섹션을 건너뛸 수 있습니다.

시작하기 위해 값 유형과 참조 유형 및 분류를 검토해 보겠습니다.

값 유형

  • 부울

  • 없는

  • 한정되지 않은

  • 숫자

단순화를 위해 이러한 유형이 단순히 스택 메모리에 값을 저장한다고 상상할 수 있습니다(기술적으로 사실이 아니지만 이 기사에서는 충분함). 예를 들어 아래 이미지에서 스택 메모리와 해당 값을 참조하십시오.

스택 메모리

참조 유형

  • 배열

  • 사물

  • 기능

이러한 유형은 힙 메모리의 실제 값을 가리키는 스택 메모리에 참조를 저장하기 때문에 조금 더 복잡합니다. 스택 메모리와 힙 메모리가 함께 작동하는 방식은 아래 예시 이미지에서 확인할 수 있습니다. 스택 메모리가 힙 메모리에 있는 참조 유형의 실제 값을 참조하는 것을 볼 수 있습니다.

스택 메모리 및 힙 메모리

값 유형과 참조 유형 간의 중요한 차이점은 값 유형의 값을 읽으려면 스택 메모리를 쿼리해야 하지만 참조 유형의 값을 읽으려면 먼저 다음을 수행해야 한다는 것입니다. 스택 메모리를 쿼리하여 참조를 가져온 다음 두 번째로 해당 참조를 사용하여 힙 메모리를 쿼리하여 참조 유형의 값을 찾습니다.

기본 전략

앞서 언급했듯이 Angular는 모델이 모든 변경 사항을 포착하는지 확인하기 위해 모델의 변경 사항을 모니터링합니다. 전체 애플리케이션 모델의 이전 상태와 현재 상태 간의 차이점을 확인합니다.

Angular가 기본 변경 감지 전략에서 묻는 질문은 다음과 같습니다. 모델의 값이 변경되었습니까? 그러나 참조 유형의 경우 더 나은 질문을 할 수 있도록 전략을 구현할 수 있습니다. 이것이 OnPush 변경 감지 전략이 필요한 곳입니다.

온푸시 전략

OnPush 전략의 기본 아이디어는 참조 유형을 변경할 수 없는 객체로 취급하면 값이 훨씬 빠르게 변경되었는지 감지할 수 있다는 깨달음에서 나타납니다. 참조 유형이 변경할 수 없는 경우 이는 업데이트될 때마다 스택 메모리의 참조가 변경되어야 함을 의미합니다. 이제 간단히 확인할 수 있습니다. 참조 유형의 참조(스택 내)가 변경되었습니까? 그렇다면 (힙에서) 모든 값을 확인하십시오. 이것이 혼란스럽다면 이전 스택 힙 다이어그램을 다시 참조하십시오.

OnPush 전략은 기본적으로 하나가 아닌 두 가지 질문을 합니다. 참조 유형의 참조가 변경되었습니까? 그렇다면 힙 메모리의 값이 변경되었습니까?

예를 들어, 30개의 요소가 있는 변경할 수 없는 배열이 있고 변경 사항이 있는지 알고 싶다고 가정합니다. 불변 배열에 대한 업데이트가 있으려면 해당 배열의 참조(스택에서)가 변경되어야 한다는 것을 알고 있습니다. 이것은 우리가 처음에 배열에 대한 참조가 다른지 확인하기 위해 확인할 수 있다는 것을 의미합니다. 그러면 잠재적으로 어떤 요소가 다른지 확인하기 위해 (힙에서) 30번의 추가 검사를 수행하지 않아도 됩니다. 이것을 OnPush 전략이라고 합니다.

따라서 참조 유형을 변경할 수 없는 것으로 취급한다는 것이 무엇을 의미하는지 물을 수 있습니다. 이는 참조 유형의 속성을 설정하지 않고 대신 값을 모두 다시 할당한다는 의미입니다. 아래 참조:

객체를 변경 가능한 것으로 취급:

 static mutable() { var before = {foo: "bar"}; var current = before; current.foo = "hello"; console.log(before === current); // => true }

객체를 불변으로 취급하기:

 static mutable() { var before = {foo: "bar"}; var current = before; current = {foo "hello"}; console.log(before === current); // => false }

위의 예에서 우리는 관례에 따라 참조 유형을 변경할 수 없는 것으로 "처리"하므로 결국 변경 가능한 객체로 작업하지만 변경 불가능한 "척"합니다.

그렇다면 구성 요소에 대한 OnPush 전략을 어떻게 구현합니까? @Component 주석에 changeDetection 매개변수를 추가하기만 하면 됩니다.

 import {ChangeDetectionStrategy, Component} from '@angular/core'; @Component({ // ... changeDetection: ChangeDetectionStrategy.OnPush }) export class OnPushComponent { // ... }

불변.js

Angular 구성 요소에서 OnPush 전략을 사용하기로 결정한 경우 불변성을 적용하는 것이 좋습니다. Immutable.js가 등장하는 곳입니다.

Immutable.js는 JavaScript의 불변성을 위해 Facebook에서 만든 라이브러리입니다. List, Map, Stack과 같은 불변 데이터 구조가 많이 있습니다. 이 기사의 목적을 위해 목록과 지도가 설명됩니다. 자세한 내용은 여기에서 공식 문서를 확인하세요.

프로젝트에 Immutable.js를 추가하려면 터미널로 이동하여 다음을 실행하세요.

 $ npm install immutable --save

또한 사용 중인 구성 요소의 Immutable.js에서 사용 중인 데이터 구조를 가져와야 합니다.

 import {Map, List} from 'immutable';

Immutable.js 맵을 사용하는 방법은 다음과 같습니다.

 var foobar = {foo: "bar"}; var immutableFoobar = Map(foobar); console.log(immutableFooter.get("foo")); // => bar

그리고 배열을 사용할 수 있습니다.

 var helloWorld = ["Hello", "World!"]; var immutableHelloWorld = List(helloWorld); console.log(immutableHelloWorld.first()); // => Hello console.log(immutableHelloWorld.last()); // => World! helloWorld.push("Hello Mars!"); console.log(immutableHelloWorld.last()); // => Hello Mars!

Immutable.js 사용의 단점

Immutable.js를 사용하는 데에는 몇 가지 논쟁의 여지가 있는 주요 단점이 있습니다.

눈치채셨겠지만 API를 사용하는 것은 약간 번거롭고 전통적인 JavaScript 개발자는 이것을 좋아하지 않을 수 있습니다. 더 심각한 문제는 Immutable.js가 인터페이스를 지원하지 않기 때문에 데이터 모델에 대한 인터페이스를 구현할 수 없다는 것과 관련이 있습니다.

마무리

OnPush 전략이 Angular의 기본 전략이 아닌 이유를 물어볼 수 있습니다. Angular가 JavaScript 개발자가 변경할 수 없는 개체로 작업하도록 하고 싶지 않았기 때문이라고 생각합니다. 하지만 그렇다고 해서 사용이 금지된 것은 아닙니다.

이것이 다음 웹 프로젝트에서 활용하고 싶은 것이라면 이제 Angular가 다른 변경 감지 전략으로 전환하는 것이 얼마나 쉬운지 알 것입니다.