각도의 경로 전체 렌더링 테스트


출신 배경


어플리케이션 성능 분석의 주요 부분 중 하나는 한 뷰에서 다른 뷰로의 라우팅을 측정하는 데 소요되는 시간*입니다.만약 당신이 시간의 추이에 따라 프로그램의 보기를 추적해서 렌더링 시간을 볼 수 있다면, 어떤 경로가 의외로 속도를 줄일 때, 당신은 강력한 하느님 같은 일별 능력을 가지고 있을 것이다.

뭐 공부 해요?


당신이 한 보기에서 다른 보기로 측정하는 데 필요한 시간을 측정할 때, 당신이 진정으로 측정하는 것은 무엇입니까?비록 우리는 오후 내내 가장 중요한 측량 항목이 무엇인지 토론할 수 있지만, 나는 다른 각도에서 볼 것이다.내가 해결해야 할 사용자 이야기를 나눠보겠습니다.

As a user, I want to measure the time it takes from when I start to navigate until the next page is fully rendered.


따라서 탐색이 시작되면 다음 보기가 완전히 렌더링되는 데 얼마나 걸릴지 알고 싶어 합니다.너무 좋아요.이제 나는 내가 측정해야 할 것이 무엇인지 알게 되었다. 나는 어떻게 각도에서 측정을 합니까?내비게이션 시작과 보기가 완전히 렌더링되는 두 가지 다른 순간을 어떻게 측정하는지 이야기해 봅시다.

탐색 시작 테스트


모든 라우터가 있는 프런트엔드 프레임워크는 탐색의 시작을 쉽게 감지할 수 있습니다.각도도 예외가 아니다.각도에서 우리는 Router 을 사용하여 이 점을 실현할 수 있다.다음은 코드 블록입니다. 우리는 그것을 실행하여 NavigationStart 개의 이벤트만 캡처하고 이벤트 발생 시간을 추적할 수 있습니다.
@Injectable({providedIn: 'root'})
export class PerfService {

    navStart$ = this.router.events.pipe(
        filter( event => event instanceof NavigationStart),
        startWith(null), // Start with something, because the app doesn't fire this on appload, only on subsequent route changes
        tap(event => /* Place code to track NavigationStart here */),
    ).subscribe();

    constructor(private router: Router) {}

}
위의 코드에서 나는 내비게이션의 시작을 성공적으로 검출했다.쉬웠어
이제 다음 보기에서 완전히 렌더링할 때 무엇을 해야 하는지 봅시다.

뷰 전체 렌더링 테스트


각도는 우리로 하여금 본질적으로 보기가 이미 완전히 렌더링되었다는 것을 알게 할 수 없다.Angular나 React에는 생명주기 연결이 하나도 없습니다. "모든 것을 고려했습니다. 저는 이미 완전히 과장했습니다."우리가 Angular에서 얻은 가장 가까운 것은 AfterViewInit 입니다. 이것은 구성 요소의 초기 보기가 렌더링되었음을 알려 줍니다.서버에 대한 요청은 모두 삭제됩니다.
그럼 이제 어떡하지?

너무 쉬운 방법


뷰가 완전히 렌더링되었는지 확인하는 가장 간단한 방법은 코드를 보는 것입니다. 모든 데이터를 읽어들여 구성 요소에 설정하면 보기가 완전히 렌더링되었다고 할 수 있습니다.
근데 생각해봐...
프로그램의 모든 구성 요소를 수정해서 Fully Rendered 이벤트를 검사하고 보고해야 합니다.이것은 세 가지 일을 의미한다.
  • 프로그램의 모든 최고급 구성 요소를 수정하고 이 사건을 보고하도록 가르쳐야 합니다.
  • 팀에서 이 사건을 미래 노선에서 보고하는 것을 잊지 않도록 감사를 만들어야 합니다.
  • Fully Rendered 작업의 코드가 전체 응용 프로그램에 분포되어 있음을 보고합니다.🤢
  • 이것은 충분한 해결 방안이 아니다.내가 뭘 했는지 알려달라고.내가 원하는 것은 모든 구성 요소를 수동으로 수정하고 프로그램에서 검사 코드를 나누어 줄 필요가 없다.나는 모든 검출 코드를 한 곳에 수집할 수 있는 연방 방법을 원한다.그럼 저는 어떻게 해야 하나요?

    완전 렌더링의 정확한 방법

    zonejs구조!Angular를 사용하는 장점 중 하나는 응용 프로그램에 이미 zonejs 가 있다는 것이다.이 문제에 대해 zonejs는 완벽하다!!
    Angular 응용 프로그램에서 주의할 만한 일이 발생하면 NgZone 불안정함을 알려 줍니다.일단 주의할 만한 모든 일이 완성되면, 그것은 너에게 그것이 또 안정되었다는 것을 알려줄 것이다.따라서 일단 NavigationStart 화재가 발생하면 NgZone 주의할 만한 모든 일이 끝난 후에 알려 달라고 요구할 수 있습니다.이러한 방식으로 응용 프로그램이 다음 보기를 능동적으로 렌더링하고 응용 프로그램이 데이터 검색을 완료하고 다음 보기를 렌더링하는 시간을 구분할 수 있습니다.너무 멋있어!
    주의할 만한 각도는 각도 영역에서 이른바 매크로 작업을 생성합니다.새 데이터나 구성 요소를 가져와서 다시 렌더링해야 할지 여부를 결정할 때마다 영역에 매크로 작업을 만듭니다.따라서 우리는 구역에 어떤 매크로 작업이 있는지 물어볼 수 있다.
    주의: 나는 zone.isStable 을 사용하지 않았습니다. 왜냐하면 때때로 zone.isStable true로 되돌아오기 때문입니다. 설령 우리가 매크로 작업이 있다 하더라도.따라서 걸린 거대한 임무를 보는 것이 좋다.NavitationStart 를 터치하면 다음 코드를 사용할 수 있습니다.
    // Once NavigationStart has fired, start checking regularly until there are
    // no more pending macrotasks in the zone
    
    // Have to run this outside of the zone, because the call to `interval`
    // is itself a macrotask. Running that `interval` inside the zone will
    // prevent the macrotasks from ever reaching zero. Running this outside
    // of Angular will not track this `interval` as a macrotask. IMPORTANT!!
    this.zone.runOutsideAngular(() => {
        // Check very regularly to see if the pending macrotasks have all cleared
        interval(10)
            .pipe(
                startWith(0), // So that we don't initially wait
                // To prevent a memory leak on two closely times route changes, take until the next nav start
                takeUntil(this.navigationStart$),
                // Turn the interval number into the current state of the zone
                map(() => !this.zone.hasPendingMacrotasks),
                // Don't emit until the zone state actually flips from `false` to `true`
                distinctUntilChanged(),
                // Filter out unstable event. Only emit once the state is stable again
                filter(stateStable => stateStable === true),
                // Complete the observable after it emits the first result
                take(1),
                tap(stateStable => {
                    // FULLY RENDERED!!!!
                    // Add code here to report Fully Rendered
                })
            ).subscribe();
    });
    
    

    와라


    이때 우리는 이미 NavigationStartFully Rendered 시간을 검출했다.우리는 지금 PerfumeJS과 같은 값을 사용하여 이 시간을 측정하기 시작할 수 있다.일단 PerfumeJS 시간을 측정하면, 우리는 이 시간을 추적하기 시작할 수 있도록 분석 데이터베이스에 넣어야 한다.
    노선에 따라 이 데이터를 보면 응용 프로그램을 매우 의미 있는 방식으로 이해할 수 있습니다.API 속도가 느려지면 영향을 받는 보기의 마운트 속도가 느려집니다. 이 테스트가 알려 줍니다.만약 누군가가 응용 프로그램의 성능에 영향을 주는 오류 코드를 검사했다면, 이것은 너에게 알려줄 것이다.
    나는 모든 사람에게 그들의 응용 프로그램 성능을 검사하고 이런 방법을 사용해서 이 점을 하도록 초청했다.

    사후 사고


    응용 프로그램에서 장시간 실행 setInterval 하는 전화가 있다면, macrotasks 응용 프로그램에서 영원히 해결되지 않을 수도 있습니다.만약 이런 방법이 당신에게 적합하지 않다면, 당신의 응용 프로그램에 또 다른 문제가 있습니다.타사 구성 요소나 라이브러리를 쉽게 찾을 수 있습니다. 이 구성 요소나 라이브러리는 setInterval 응용 프로그램 영역이 0으로 복구되는 것을 막는 대기 매크로 작업을 가지고 있습니다.이 문제들을 어떻게 발견하고 해결하는지는 다른 블로그 게시물의 주제이고, 다른 날이다.만약 누군가가 이런 상황을 겪고 그것을 복구하는 방법에 대해 이야기하고 싶다면 트위터에 DM을 보내주세요:)

    별생각


    * 어플리케이션 성능 측정에 가장 중요한 요소...가늠해야 할 일이 많다.첫 번째 바이트나 첫 번째 의미 있는 내용까지 시간.이 글은 결코 이것이 전단 성능 측정에서 가장 중요한 부분이라고 말하는 것이 아니다.그러나 응용 프로그램의 움직임을 관찰할 때 이것은 매우 중요할 것이다.

    좋은 웹페이지 즐겨찾기