다음을 통해 공유


크고 복잡한 캔버스 앱 빌드

설명서의 이 섹션에 있는 대부분의 문서에서는 앱 사용 사용자가 경험한 앱의 런타임 성능을 다룹니다. 이 문서에서는 앱을 만드는 사람들이 경험하는 앱 성능에 대해 설명합니다.

앱이 점점 더 복잡해짐에 따라 Power Apps Studio는 더 많은 수의 컨트롤, 수식 및 데이터 원본을 로드하고 관리해야 하며, 모두 기하급수적으로 증가하는 상호 종속성이 있습니다. Power Apps Studio를 로드하는 데 시간이 오래 걸릴 수 있으며 IntelliSense 및 색 코딩과 같은 기능은 지연될 수 있습니다. Power Apps Studio에서 크고 복잡한 앱으로 더 잘 작동하려면 다음 권장 사항을 사용합니다. 또한 앱의 런타임 성능을 개선하는 데 도움이 될 수 있습니다.

이 문서의 예제에서는 병원 응급 대응 샘플 솔루션을 사용합니다.

App.OnStart 대신 App.Formulas 사용

팁 (조언)

명명된 수식 대신 With 함수 및 캔버스 구성 요소 사용자 지정 출력 속성을 사용할 수 있습니다.

Power Apps Studio와 앱의 로드 시간을 줄이는 가장 좋은 방법은 App.OnStart의 변수 및 컬렉션 초기화를 App.Formulas의 명명된 수식으로 바꾸는 것입니다.

App.OnStart를 사용하는 다음 예제를 살펴보겠습니다.

// Get the color of text on a dark background.
Set(varColorOnDark,RGBA(0, 0, 0, 1));

// Get the color of the menu icons.
Set(varColorMenuIcon,"#0070a9");

// Get the styles for a form.
Set(varFormStyle,
    {
        DataCard: { Height: 50 },
        Title: { Height: 50, Size: 21, Color: varColorOnDark },
        Control: { Height: 50, Size: 18 },
        Label: { Size: 18, Color: varColorOnDark }
    }
);

ClearCollect(
    FacilitiesList,
    ForAll(
        Facilities,
        { Name: 'Facility Name', Id: Facility }
    )
);
If(
    Not IsBlank(Param("FacilityID")),
    Set(ParamFacility,
        LookUp(
            FacilitiesList,
            Id = GUID(Param("FacilityID"))
        ).Name
    );
);

명령문의 시퀀스이므로 앱은 첫 번째 화면을 표시하기 전에 이러한 SetCollect 호출을 순서대로 평가해야 하므로 앱 로드 속도가 더 느려집니다. 또한 최종 결과를 반환하기 전에 전체 App.OnStart , 순서 유지 및 오류를 집계해야 하므로 Power Apps Studio에서 분석하기 위한 수식은 복잡합니다.

더 나은 방법이 있습니다. 대신 App.Formulas를 사용하고 다음 예제와 같이 이러한 변수와 컬렉션을 명명된 수식으로 정의합니다.

// Get the color of text on a dark background.
varColorOnDark = RGBA(0, 0, 0, 1);

// Get the color of the menu icons.
varColorMenuIcon = "#0070a9";

// Get the styles for a form.
varFormStyle = 
    {
        DataCard: { Height: 50 },
        Title: { Height: 50, Size: 21, Color: varColorOnDark },
        Control: { Height: 50, Size: 18 },
        Label: { Size: 18, Color: varColorOnDark }
    };

FacilitiesList =
    ForAll(
        Facilities,
        { Name: 'Facility Name', Id: Facility }
    );

ParamFacility = 
    If( Not IsBlank(Param("FacilityID")),
        LookUp(
            FacilitiesList,
            Id = GUID(Param("FacilityID"))
        ).Name,
        Blank()
    );

이러한 변화는 작게 보일 수 있지만 큰 영향을 미칠 수 있습니다. 명명된 각 수식은 다른 수식과 독립적이므로 Power Apps Studio는 독립적으로 분석하여 큰 App.OnStart 를 더 작은 조각으로 효과적으로 분할할 수 있습니다. 이 변경만으로도 Power Apps Studio 로드 시간이 80% 감소하는 것을 보았습니다.

또한 앱은 결과가 필요할 때까지 이러한 수식을 평가할 필요가 없으므로 더 빠르게 로드됩니다. 앱의 첫 번째 화면이 즉시 표시됩니다.

명명된 수식은 수정하거나 Set에서 사용할 수 없으므로 모든 상황에서 사용할 수 없습니다. 일부 상황에서는 수정할 수 있는 상태 변수를 사용해야 합니다. 설정 은 이러한 상황에 적합하며 계속 사용해야 합니다. 하지만 OnStart 에서 전역 변수를 사용하여 변경되지 않는 정적 값을 설정하는 경우가 많습니다. 이러한 경우 명명된 수식이 더 나은 선택입니다.

명명된 수식은 변경할 수 없으므로 명명 규칙으로 접두사 var ("변수"의 약자)는 더 이상 적절하지 않습니다. 이 예제에서는 앱의 나머지 부분과 일치하도록 변경해야 하므로 이름을 변경하지 않았습니다.

App.OnStart에 명명된 수식을 배치하는 것은 유혹적이지만 그렇지 않습니다. 그들은 거기에 속하지 않습니다. On 동작 속성으로 App.OnStart는 앱이 로드될 때 각 문을 순서대로 평가하고 전역 변수를 만들고 데이터베이스와 한 번만 통신합니다. 명명된 수식은 필요할 때마다 계산하는 방법을 정의하는 수식이며 항상 true입니다. 이러한 수식 특성은 독립성을 허용하고 앱이 평가되기 전에 로드를 완료할 수 있도록 하는 것입니다.

긴 수식을 분할하기

App.OnStart 는 긴 수식에 대한 최악의 범죄자 중 하나이며 반드시 시작해야 할 곳 중 하나이지만 유일한 경우는 아닙니다.

연구에 따르면 Power Apps Studio의 로드 시간이 긴 거의 모든 앱에는 256,000자 이상의 수식이 하나 이상 있습니다. 로드 시간이 가장 긴 일부 앱에는 100만 자 이상의 수식이 있습니다. 오랫동안 Power Apps Studio에 상당한 부담을 주는 수식입니다.

긴 수식이 포함된 컨트롤을 복사하여 붙여넣으면 컨트롤 속성에 수식이 중복되지만, 그것이 인식되지 않습니다. Power Apps는 수식의 여러 복사본이 공통적인 Excel을 모델로 합니다. 그러나 Excel에서 수식은 하나의 식으로 제한되며 8,000자로 제한됩니다. Power Apps 수식은 명령적 논리 및 체인 연산자(; 또는 ;;로캘에 따라 다름)가 도입되면서 훨씬 더 길어질 수 있습니다.

일반적인 해결 방법은 App.OnStart의 /Collect 문을 App.Formulas의 명명된 수식으로 변경했을 때 이전 섹션에서 했던 것처럼 긴 수식을 더 작은 부분으로 분할하고 부품을 다시 사용하는 것입니다. 다른 프로그래밍 언어에서는 재사용 가능한 부분을 하위 경로 또는 사용자 정의 함수라고도 합니다. 명명된 수식은 매개 변수나 부작용이 없는 간단한 형태의 사용자 정의 함수로 생각할 수 있습니다.

모든 곳에서 명명된 수식 사용

이전 예제에서는 App.OnStart의 대체 수식으로 명명된 수식을 사용했습니다. 그러나 이를 사용하여 앱의 어느 곳에서나 계산을 바꿀 수 있습니다.

예를 들어, 병원 응급 대응 샘플 솔루션의 한 화면에는 이 논리가 Screen.OnVisible에 포함되어 있습니다.

ClearCollect(
    MySplashSelectionsCollection,
    {
        MySystemCol: First(
            Filter(
                Regions,
                Region = MyParamRegion
            )
        ).System.'System Name',
        MyRegionCol: First(
            Filter(
                Regions,
                Region = MyParamRegion
            )
        ).'Region Name',
        MyFacilityCol: ParamFacility,
          MyFacilityColID:  LookUp(
            FacilitiesList,
            Id = GUID(Param("FacilityID"))
        ).Id
    }
); 

이 수식은 명명된 수식 집합으로 분할할 수 있습니다. 또한 수식을 더 쉽게 읽을 수 있습니다.

MyRegion = LookUp(
                    Regions,
                    Region = MyParamRegion
           );

MyFacility = LookUp(
                    FacilitiesList,
                    Id = GUID(Param("FacilityID")
            );

MySplashSelectionsCollection = 
    {
        MySystemCol: MyRegion.System.'System Name',
        MyRegionCol: MyRegion.'Region Name',
        MyFacilityCol: ParamFacility,
        MyFacilityColID:  MyFacility.Id
    };

이전에 App.OnStart에서 Set 호출의 대부분을 App.Formulas의 명명된 수식으로 이동했을 때 ParamFacility를 명명된 수식으로 추출했습니다.

명명된 수식은 해당 값이 필요한 경우에만 평가됩니다. Screen.OnVisible을 사용하려는 원래 의도가 화면이 표시될 때까지 작업을 연기하려는 경우 작업은 App.Formulas에서 전역 명명된 수식으로 계속 지연됩니다.

With 함수 사용

수식에서 With 함수를 사용하여 논리를 분할할 수도 있습니다. 첫 번째 매개 변수에 필드로 사용할 값을 사용하여 레코드를 만든 다음 두 번째 매개 변수의 해당 필드를 사용하여 With의 반환 값을 계산합니다. 예를 들어 이전 예제는 하나의 명명된 수식으로 작성할 수 있습니다.

MySplashSelectionsCollection = 
    With( { MyRegion: LookUp(
                            Regions,
                            Region = MyParamRegion
                      ),
            MyFacility: LookUp(
                            FacilitiesList,
                            Id = GUID(Param("FacilityID")
                      ) 
           },
           {
                MySystemCol: MyRegion.System.'System Name',
                MyRegionCol: MyRegion.'Region Name',
                MyFacilityCol: ParamFacility,
                MyFacilityColID:  MyFacility.Id
           }
    )

With를 이 방식으로 사용하는 한 가지 단점은 MyFacilityMyRegion이(가) 동일한 With 함수에 정의되어 있어 사용할 수 없다는 점이며, 이러한 문제는 명명된 수식을 사용할 때는 발생하지 않습니다. 한 가지 해결 방법은 With 함수를 중첩하고 As 키워드를 사용하여 각각에 대한 레코드 이름을 지정하여 모든 With 변수에 쉽게 액세스할 수 있도록 하는 것입니다.

캔버스 구성 요소 사용

캔버스 구성 요소는 컨트롤처럼 캔버스에 배치할 수 있는 UI 컨트롤을 만드는 데 가장 자주 사용됩니다. 명명된 수식 대신 사용자 지정 출력 속성을 사용하여 계산을 수행하기 위해 UI에 배치하지 않고 사용할 수도 있습니다. 캔버스 구성 요소는 구성 요소 라이브러리를 사용하여 앱 간에 쉽게 공유할 수 있으며 명명된 수식과 달리 완전히 지원됩니다. 그러나 명명된 수식보다 구성하고 사용하기가 더 어렵습니다.

논리를 분할하려면 다음을 수행합니다.

  1. Power Apps Studio에서 트리 보기구성 요소 탭으로 전환합니다.
  2. 새 구성 요소를 만듭니다.
  3. 속성 창에서 Access 앱 범위를 켭니다.
  4. 사용자 지정 속성을 추가합니다.
  5. 속성 형식출력으로 설정하고 데이터 형식을 적절하게 설정합니다.
  6. 선택하고생성합니다.
  7. 화면 맨 위에 있는 수식 입력줄 옆의 속성 선택기에서 새 속성을 선택합니다.
  8. 분할하고 다시 사용할 논리에 대한 수식을 작성합니다.

논리를 사용하려면 다음을 수행합니다.

  1. 트리 보기화면 탭으로 전환합니다.
  2. 삽입 창에서 사용자 지정을 확장하고 구성 요소를 삽입합니다.
  3. 속성을 사용하여 값을 계산하려면 ComponentName.PropertyName을 사용합니다.

명령적 논리를 위해 숨겨진 컨트롤을 사용하여 선택 기능을 활용하세요.

명령적 논리는 설정수집을 사용하여 상태를 수정하고, 알림으로 사용자에게 알리고, 탐색 및 시작을 사용하여 다른 화면 또는 앱으로 이동하고, 패치, SubmitForm 또는 RemoveIf를 사용하여 데이터베이스에 값을 쓰는 데 사용됩니다.

명명된 수식 및 캔버스 구성 요소 사용자 지정 출력 속성은 명령적 논리를 지원하지 않습니다. 명령적 논리를 분할하는 일반적인 방법은 숨겨진 컨트롤의 OnSelect 속성을 사용하는 것입니다.

  1. 화면에 단추 컨트롤을 추가합니다.
  2. OnSelect 속성을 실행하려는 명령적 논리로 설정합니다.
  3. 사용자가 보거나 상호 작용할 필요가 없으므로 Visible 속성을 false로 설정합니다.
  4. 명령적 논리를 실행하려는 경우 호출 Select( Button ) 합니다.

예를 들어 샘플의 화면 중 하나에는 단추 컨트롤이 있으며, OnSelect 속성이 다음과 같습니다. (이 간단한 예제는 설명 용도로만 사용됩니다. 일반적으로 이 기술은 더 긴 수식에만 사용합니다.)

btnAction_17.OnSelect = 
    Trace("Feedback Screen: Submit Button",TraceSeverity.Information);
    If(
        // Proceed if all forms are validated.
        And(
            FormFeedback.Valid
        ),
    
        // Set the updates to static variables.
        Set(updatesFeedback,Patch(Defaults('App Feedbacks'), FormFeedback.Updates));
        // Submit the first form. Subsequent actions can be found in the OnSuccess.
        SubmitForm(FormFeedback);
        ,
    
        Notify("Please complete all fields before proceeding",
               NotificationType.Warning,2000)
    );

이 논리를 부분으로 분할하려면 부분을 별도의 단추 컨트롤에 배치하고 원본에서 선택합니다 .

btnTrace.OnSelect = 
    Trace("Feedback Screen: Submit Button",TraceSeverity.Information);

btnSubmit.OnSelect = 
    If(
        // Proceed if all forms are validated.
        And(
            FormFeedback.Valid
        ),
    
        // Set the updates to static variables.
        Set(updatesFeedback,Patch(Defaults('App Feedbacks'), FormFeedback.Updates));
        // Submit the first form. Subsequent actions can be found in OnSuccess.
        SubmitForm(FormFeedback);
        ,
    
        Notify("Please complete all fields before proceeding",
               NotificationType.Warning,2000)
    );

btnAction_17.OnSelect = 
    Select( btnTrace );
    Select( btnSubmit );

이 기술은 동일한 화면에서만 작동합니다. 토글 컨트롤을 사용하고, OnCheck을 실행하려는 논리로 설정하고, Default를 전역 변수로 설정한 다음, 논리를 실행하려는 시점으로 전역 변수 Set( global, true ); Set( global, false ) 를 토글하는 등 화면에서 약간 더 복잡한 다른 기술이 작동합니다.

이 예제에서는 일부 논리 분할이 이미 수행되었습니다. 주석은 "후속 작업은 OnSuccess에서 찾을 수 있습니다."라고 언급합니다. 이 이벤트는 레코드가 성공적으로 제출된 후 SubmitForm 함수와 관련된 솔루션인 명령적 논리를 실행합니다.

앱 분할

일부 앱은 수천 개의 컨트롤과 수백 개의 데이터 원본으로 확장되어 Power Apps Studio 속도가 느려집니다. 긴 수식과 마찬가지로 큰 앱을 하나의 사용자 환경을 만들기 위해 함께 작동하는 더 작은 섹션으로 분할할 수 있습니다.

별도의 캔버스 앱

한 가지 방법은 별도의 캔버스 앱에서 섹션을 구현하고 Launch 함수를 사용하여 별도의 앱 간을 탐색하고 필요한 컨텍스트를 전달하는 것입니다.

이 방법은 병원 응급 대응 샘플 솔루션에서 사용되었습니다. 개별 앱은 전체 앱의 각 주요 영역을 관리합니다. 앱은 각 앱이 시작 화면에 표시하는 구성 요소 라이브러리를 통해 공통 스위치보드 구성 요소를 공유합니다.

스위치보드 캔버스 구성 요소를 보여 주는 휴대폰에서 실행되는 병원 응급 대응 샘플 솔루션 캔버스 앱의 스크린샷.

사용자가 영역을 선택하면 구성 요소는 사용 가능한 앱 및 구성 요소를 호스팅하는 앱에 대한 메타데이터를 사용합니다. 원하는 화면이 이 앱에 있는 경우(즉, ThisItem.Screen 이 비어 있지 않음) Navigate 호출이 수행됩니다. 그러나 원하는 화면이 다른 앱에 있는 경우(즉, ThisItem.PowerAppID 가 비어 있지 않음) 실행 함수는 대상의 앱 ID 및 FacilityID 컨텍스트와 함께 사용됩니다.

If(
    IsBlank(ThisItem.Screen),
    If(IsBlank(ThisItem.PowerAppID), 
        Launch(ThisItem.URL),           
        Launch("/providers/Microsoft.PowerApps/apps/" & ThisItem.PowerAppID, 
               "FacilityID", Home_Facility_DD.Selected.Id)
    ),
    Navigate(
        ThisItem.Screen,
        Fade
    )
);

다른 앱을 시작하면 원래 앱의 상태가 손실됩니다. Launch 함수를 호출하기 전에 상태를 저장해야 합니다. 데이터베이스에 기록하거나 SaveData를 호출하거나, Param 함수로 읽는 매개 변수를 사용하여 대상 앱에 상태를 전달합니다.

사용자 지정 페이지가 있는 모델 기반 앱

섹션을 사용자 지정 페이지로 구현할 수도 있습니다. 사용자 지정 페이지는 탐색을 위한 모델 기반 앱 컨테이너가 있는 미니 캔버스 앱 역할을 합니다.