Compartir a través de


Crear aplicaciones de lienzo grandes y complejas

La mayoría de los artículos de esta sección de los documentos cubren el rendimiento del tiempo de ejecución de las aplicaciones tal como lo experimentan los que las usan. Este artículo cubre el rendimiento de las aplicaciones tal como lo experimentan las personas que las crean.

A medida que las aplicaciones se vuelven más grandes y complejas, Power Apps Studio necesita cargar y administrar una mayor cantidad de controles, fórmulas y orígenes de datos, todos con interdependencias que crecen exponencialmente. El tiempo de carga de la aplicación para Power Apps Studio puede ralentizarse y las características como IntelliSense y la codificación de colores pueden retrasarse. Utilice las recomendaciones siguientes para trabajar mejor con aplicaciones grandes y complejas en Power Apps Studio. También pueden ayudar a mejorar el rendimiento del tiempo de ejecución de sus 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 forma de reducir el tiempo de carga para Power Apps Studio y su aplicación es sustituir la inicialización de variables y colecciones en App.OnStart por fórmulas con nombre en App.Formulas.

Echemos un vistazo con el 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
    );
);

Como son una secuencia de instrucciones, su aplicación debe evaluar estas llamadas a Set y Collect deben evaluarse en orden antes de que se muestre la primera pantalla, lo que ralentiza el tiempo de carga de la aplicación. Y debido a que toda la App.OnStart debe considerarse como un todo, conservar el orden y agregar los errores y antes de devolver el resultado final, la fórmula que analiza Power Apps Studio es compleja.

Hay una mejor forma. 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. Como cada fórmula nombrada es independiente de las demás, Power Apps Studio puede analizarlos de forma independiente, dividiendo efectivamente una App.OnStart en pedazos más pequeños. Hemos visto que el tiempo de carga de Power Apps Studio se reduce hasta en un 80 % solo con este cambio.

Su 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 debe continuar usándolo. Pero, la mayoría de las veces, estás usando 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 (abreviatura de "variable") como convención de nomenclatura ya no es apropiado. No cambiamos los nombres en este ejemplo porque requeriría cambios en el resto de la aplicación para que coincidan.

Es tentador colocar una fórmula con nombre en App.OnStart, pero no es su lugar. Ellos 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 con nombre son fórmulas que definen cómo calcular algo siempre que sea necesario y siempre son verdaderas. Es esta naturaleza de fórmula la que les permite ser independientes y permite que la aplicación termine de cargarse antes de evaluarse.

Dividir fórmulas largas

App.OnStart es uno de los peores infractores de las fórmulas largas y sin duda por donde debe empezar, pero no es el único caso.

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

Para empeorar las cosas, copiar y pegar un control con un fórmula larga duplicará la fórmula en las propiedades del control sin que se dé cuenta. Power Apps sigue el modelo de Excel, donde son comunes varias copias de una fórmula. Sin embargo, en Excel, las fórmulas están limitadas a una expresión y tienen un límite de 8000 caracteres. Las fórmulas de Power Apps pueden hacerse mucho más largas con la introducción de la lógica imperativa y el operador de encadenamiento (; o ;;, según la configuración regional).

La solución general es dividir las fórmulas largas en partes más pequeñas y reutilizar esas partes, como se hizo anteriormente con el cambio de las instrucciones de Set/Collect en App.OnStart a fórmulas con nombre en App.Formulas. En otros lenguajes de programación, estas partes reutilizables suelen denominarse subrutinas o funciones definidas por el usuario. Puede ver las fórmulas con nombre pueden considerarse como una forma sencilla de funciones definidas por el usuario sin parámetros o 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 usarlas para reemplazar un cálculo en cualquier lugar de una aplicación.

Por ejemplo, una de las pantallas de la solución de ejemplo Respuesta a emergencias hospitalarias 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 hace que la fórmula sea más fácil de leer.

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

Extraemos ParamFacility anteriormente como fórmula con nombre cuando trasladamos la mayoría de las llamadas a Set desde App.OnStart a fórmulas con nombre en App.Formulas.

Las fórmulas con nombre se evalúan solo cuando se necesitan sus valores. Si la intención original de usar Screen.OnVisible era aplazar el trabajo hasta que se mostrara la pantalla, entonces el trabajo se seguirá aplazando como fórmulas globales con nombre en App.Formulas.

Usar la función With

También puede usar la función With en una fórmula para dividir la lógica. Crear un registro en el primer parámetro con los valores deseados como campos, y luego usar esos campos en el segundo parámetro para calcular el valor de retorno de With. Por ejemplo, el ejemplo anterior puede escribirse como una sola 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 es anidar funciones With y usar la palabra clave As para asignar un nombre al registro de cada una de ellas para facilitar el acceso a todas las variables With.

Usar componentes de lienzo

Los componentes de lienzo se usan con mayor frecuencia para crear un control de interfaz de usuario que pueda colocarse en el lienzo como si fuera un control. También pueden usarse sin colocarse en la IU para realizar cálculos con propiedades de salida personalizadas, lo que constituye una 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 en la Vista de árbol.
  2. Crear un nuevo componente.
  3. En el panel Propiedades, active Acceder al ámbito de la aplicación.
  4. Agregue una propiedad personalizada.
  5. Establezca el Tipo de propiedad como Salida y el Tipo de datos como corresponda.
  6. Seleccione Crear.
  7. En el selector de propiedad junto a la barra de fórmulas en 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 Insertar, expanda Personalizar e inserte su componente.
  3. Para calcular un valor con la propiedad, use ComponentName.PropertyName.

Usar Select con un control oculto para la lógica imperativa

La lógica imperativa se usa para modificar el estado con Set y Collect, avisar al usuario con Notify, navegar a otra pantalla o aplicación con Navigate y 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 la lógica imperativa. Un truco común para dividir la lógica imperativa es usar la propiedad OnSelect de un control oculto.

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

Por ejemplo, una de las pantallas de nuestra muestra tiene la siguiente propiedad OnSelect en un control Botón. (Este ejemplo simple 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 en todas las pantallas, como usar el control Control de alternancia, establecer OnCheck en la lógica desea ejecutar y establecer Default en una variable global y luego alternar la variable global con Set( global, true ); Set( global, false ) en el punto en el que 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 una lógica imperativa después de que el registro se haya enviado correctamente, una solución específica de la función SubmitForm.

Particionar la aplicación

Algunas aplicaciones crecen hasta tener miles de controles y cientos de fuentes 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 sola experiencia de usuario.

Separar aplicaciones de lienzo

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

Este enfoque se utilizó en la solución de muestra Hospital Emergency Response. Las aplicaciones separadas administran cada una de las áreas principales de la aplicación general. Las aplicaciones comparten un componente de panel de control común 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 acerca de las aplicaciones disponibles y qué aplicación hospeda el componente. Si la pantalla deseada se encuentra en esta aplicación (es decir, ThisItem.Screen no está en blanco), entonces se realiza una llamada a Navigate. Pero si la pantalla deseada se encuentra en una aplicación diferente (esto es, 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 perderá cuando se ejecute 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 que se leen con la función Param.

Aplicación basada en modelo 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.

Nota

¿Puede indicarnos sus preferencias de idioma de documentación? Realice una breve encuesta. (tenga en cuenta que esta encuesta está en inglés)

La encuesta durará unos siete minutos. No se recopilan datos personales (declaración de privacidad).