Compartir a través de


Crear aplicaciones de lienzo grandes y complejas

La mayoría de los artículos de esta sección de la documentación tratan el rendimiento en tiempo de ejecución de las aplicaciones según la experiencia de las personas que las usan. En este artículo se describe el rendimiento de las aplicaciones según la experiencia de las personas que las hacen.

A medida que las aplicaciones se vuelven más grandes y complejas, Power Apps Studio debe cargar y administrar un mayor número de controles, fórmulas y orígenes de datos, todo ello con interdependencias que crecen exponencialmente. Power Apps Studio puede tardar más tiempo en cargarse y las características como IntelliSense y la codificación de colores pueden retardar. Use las recomendaciones siguientes para trabajar mejor con aplicaciones grandes y complejas en Power Apps Studio. También pueden ayudar a mejorar el rendimiento en tiempo de ejecución de las aplicaciones.

Todos los ejemplos de este artículo usan la solución de muestra Hospital Emergency Response.

Usar App.Formulas en lugar de App.OnStart

Sugerencia

Puede utilizar la función With y propiedades de salida personalizadas del componente de lienzo como alternativa a las fórmulas con nombre.

La mejor manera de reducir el tiempo de carga para Power Apps Studio y la aplicación es reemplazar la inicialización de variables y colecciones en App.OnStart con fórmulas con nombre en App.Formulas.

Echemos un vistazo al ejemplo siguiente, que usa 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
    );
);

Dado que son una secuencia de instrucciones, la aplicación debe evaluar estas llamadas Set y Collect en orden para poder mostrar la primera pantalla, lo que hace que la aplicación se cargue más lentamente. Además, dado que todo el App.OnStart debe considerarse como un todo, manteniendo el orden y asegurando que los errores se agreguen antes de devolver el resultado final, la fórmula resulta compleja para que Power Apps Studio la analice.

Hay una mejor manera. Use App.Formulas en su lugar y defina estas variables y colecciones como fórmulas con nombre, como en el ejemplo siguiente.

// 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()
    );

Este cambio puede parecer pequeño, pero puede tener un gran impacto. Dado que cada fórmula con nombre es independiente de las demás, Power Apps Studio puede analizarlas de forma independiente y dividir eficazmente una aplicación.OnStart grande en partes más pequeñas. Hemos observado que el tiempo de carga de Power Apps Studio ha disminuido hasta un 80% únicamente con este cambio.

La aplicación también se carga más rápido porque no tiene que evaluar estas fórmulas hasta que necesite el resultado. La primera pantalla de la aplicación se muestra inmediatamente.

Las fórmulas con nombre no se pueden usar en todas las situaciones porque no se pueden modificar ni usar con Set. Algunas situaciones requieren el uso de una variable de estado que se puede modificar. Set es perfecto para estas situaciones y debería seguir utilizándolo. Pero, con más frecuencia que no, usa variables globales en OnStart para configurar valores estáticos que no cambian. En esos casos, una fórmula con nombre es la mejor opción.

Dado que las fórmulas con nombre son inmutables, el prefijo var (corto para "variable") como convención de nomenclatura ya no es adecuado. No se cambiaron los nombres de este ejemplo porque requerirían cambios en el resto de la aplicación para que coincidan.

Es tentador colocar una fórmula con nombre en App.OnStart, pero no. No pertenecen allí. Como propiedad de comportamiento On, App.OnStart evalúa cada una de sus instrucciones en orden, creando variables globales y comunicándose con las bases de datos solo una vez, cuando se carga la aplicación. Las fórmulas nombradas son fórmulas que definen cómo calcular algo cuando sea necesario y siempre son verdaderas. Es la naturaleza de esta fórmula lo que les permite funcionar de manera independiente y permite que la aplicación complete su carga antes de ser evaluadas.

Desglosar fórmulas largas

App.OnStart es uno de los aspectos más problemáticos para fórmulas extensas y definitivamente donde deberías comenzar, sin embargo, no es el único caso.

Nuestros estudios han demostrado que casi todas las aplicaciones con un tiempo de carga largo para Power Apps Studio tienen al menos una fórmula de más de 256 000 caracteres. Algunas aplicaciones con los tiempos de carga más largos tienen fórmulas de más de 1 millón de caracteres. Fórmulas que durante mucho tiempo han supuesto una carga significativa en Power Apps Studio.

Para empeorar las cosas, copiar y pegar un control con una fórmula larga duplica la fórmula en las propiedades del control sin que el usuario se dé cuenta. Power Apps se modela después de Excel, donde varias copias de una fórmula son comunes. Sin embargo, en las fórmulas de Excel se limitan a una expresión y se limitan a 8000 caracteres. Las fórmulas de Power Apps pueden crecer mucho más con la introducción de la lógica imperativa y el operador de encadenamiento (; o ;;, dependiendo de la configuración regional).

La solución general consiste en dividir fórmulas largas en partes más pequeñas y reutilizar las partes, como hicimos en la sección anterior cuando cambiamos Set/las declaraciones Collect en App.OnStart por fórmulas con nombre en App.Formulas. En otros lenguajes de programación, las partes reutilizables suelen denominarse subrutinas o funciones definidas por el usuario. Puede considerar fórmulas con nombre como una forma sencilla de función definida por el usuario sin parámetros ni efectos secundarios.

Usar fórmulas con nombre en todas partes

En el ejemplo anterior, usamos fórmulas con nombre como reemplazo de App.OnStart. Sin embargo, puede usarlos para reemplazar un cálculo en cualquier parte de una aplicación.

Por ejemplo, una de las pantallas de la solución de ejemplo de respuesta de emergencia hospitalaria incluye esta lógica en 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
    }
); 

Esta fórmula se puede dividir en un conjunto de fórmulas con nombre. También facilita la lectura de la fórmula.

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
    };

Hemos extraído ParamFacility como una fórmula con nombre anteriormente cuando hemos movido la mayoría de las llamadas Set de App.OnStart a fórmulas con nombre en App.Formulas.

Las fórmulas con nombre solo se evalúan cuando se necesitan sus valores. Si la intención original de usar Screen.OnVisible era aplazar el trabajo hasta que se muestre la pantalla, el trabajo todavía se aplaza como fórmulas con nombre global en App.Formulas.

Uso de la función With

También puede usar la función With en una fórmula para dividir la lógica. Cree un registro en el primer parámetro con los valores que desea usar como campos y, a continuación, use esos campos en el segundo parámetro para calcular el valor devuelto de With. Por ejemplo, el ejemplo anterior se puede escribir como una fórmula con nombre:

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
           }
    )

Una desventaja de usar With de esta forma es que MyFacility no puede usar MyRegion porque están definidas dentro de la misma función With, un problema que no presentan las fórmulas con nombre. Una solución consiste en anidar funciones With y usar la palabra clave As para nombrar el registro de cada función, facilitando así el acceso a todas las variables With.

Uso de componentes de lienzo

Los componentes de lienzo se utilizan más frecuentemente para crear un control de interfaz de usuario que se puede colocar en el lienzo igual que cualquier otro control. También puede usarlos sin colocarlos en la interfaz de usuario para realizar cálculos con propiedades de salida personalizadas como alternativa a las fórmulas con nombre. Los componentes de lienzo son fáciles de compartir entre aplicaciones con bibliotecas de componentes y son totalmente compatibles, a diferencia de las fórmulas con nombre. Sin embargo, son más difíciles de configurar y usar que las fórmulas con nombre.

Para dividir la lógica:

  1. En Power Apps Studio, cambie a la pestaña Componentes de la vista Árbol.
  2. Cree un nuevo componente.
  3. En el panel Propiedades, active Acceso al ámbito de la aplicación.
  4. Agregue una propiedad personalizada.
  5. Establezca el tipo de propiedad en Salida y el tipo de datos según corresponda.
  6. Selecciona Crear.
  7. En el selector de propiedades situado junto a la barra de fórmulas de la parte superior de la pantalla, seleccione la nueva propiedad.
  8. Escriba la fórmula de la lógica para dividir y reutilizar.

Para usar la lógica:

  1. Cambie a la pestaña Pantallas en la Vista de árbol.
  2. En el panel Insert, expanda Personalizado e inserte su componente.
  3. Para calcular un valor con la propiedad , use ComponentName.PropertyName.

Uso de Select con un control oculto para la lógica imperativa

La lógica imperativa se usa para modificar el estado con Set y Collect, notificar al usuario con Notify, navegar a otra pantalla o aplicación con Navigate e Launch y escribir valores en una base de datos con Patch, SubmitForm o RemoveIf.

Las fórmulas con nombre y las propiedades de salida personalizadas del componente de lienzo no admiten lógica imperativa. Una manera común de dividir la lógica imperativa es usar la propiedad OnSelect de un control oculto.

  1. Agregue un control Button a una pantalla.
  2. Establezca la propiedad OnSelect en la lógica imperativa que desea ejecutar.
  3. Establezca la propiedad Visible en false, ya que no es necesario que el usuario vea o interactúe con él.
  4. Llame Select( Button ) a cuando quiera ejecutar la lógica imperativa.

Por ejemplo, una de las pantallas de nuestro ejemplo tiene la siguiente propiedad OnSelect en un control Button . (Este ejemplo sencillo es solo para fines ilustrativos. Normalmente, solo usaría esta técnica para fórmulas más largas).

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)
    );

Para dividir esta lógica en partes, podemos poner partes en controles Botón independientes y seleccionarlos con Select en el original:

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 );

Esta técnica solo funciona en la misma pantalla. Otras técnicas que son un poco más complicadas funcionan a través de las pantallas, como usar el control Alternar, configurar OnCheck a la lógica que desea ejecutar, establecer Default a una variable global, y luego alternar la variable global utilizando Set( global, true ); Set( global, false ) en el punto donde desea ejecutar la lógica.

En este ejemplo, ya se había realizado alguna división lógica. El comentario menciona que "Las acciones posteriores se pueden encontrar en OnSuccess". Este evento ejecuta la lógica imperativa después de que el registro se haya enviado correctamente, una solución específica de la función SubmitForm .

Partición de la aplicación

Algunas aplicaciones crecen hasta miles de controles y cientos de orígenes de datos, lo que ralentiza Power Apps Studio. Al igual que con las fórmulas largas, las aplicaciones grandes se pueden dividir en secciones más pequeñas que funcionan juntas para crear una experiencia de usuario.

Separar aplicaciones de lienzo

Un enfoque consiste en implementar secciones en aplicaciones de lienzo independientes y usar la función Launch para navegar entre las aplicaciones independientes y pasar el contexto necesario.

Este enfoque se usó en la solución de ejemplo de respuesta de emergencia del hospital. Las aplicaciones independientes administran cada una de las áreas principales de la aplicación general. Las aplicaciones comparten un componente común del panel de conmutadores a través de una biblioteca de componentes que cada aplicación muestra en su pantalla de inicio:

Captura de pantalla de la aplicación de lienzo de solución de muestra Hospital Emergency Response que se ejecuta en un teléfono, mostrando el componente de lienzo de centralita.

Cuando el usuario selecciona un área, el componente usa metadatos sobre las aplicaciones disponibles y qué aplicación hospeda el componente. Si la pantalla deseada está en esta aplicación (es decir, ThisItem.Screen no está en blanco), se realiza una llamada navigate . Pero si la pantalla deseada está en una aplicación diferente (es decir, ThisItem.PowerAppID no está en blanco), se usa una función Launch con el identificador de aplicación del destino y el contexto 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
    )
);

El estado de la aplicación original se pierde cuando se inicia otra aplicación. Asegúrese de guardar cualquier estado antes de llamar a la función Launch . Escríbalo en una base de datos, llame a SaveData o pase el estado a la aplicación de destino con parámetros leídos con la función Param .

Aplicación controlada por modelos con páginas personalizadas

Las secciones también se pueden implementar como páginas personalizadas. Las páginas personalizadas actúan como una miniaplicación de lienzo, con un contenedor de aplicaciones basadas en modelo para la navegación.