Partilhar via


Estruturar formulários para desempenho em aplicações condicionadas por modelo

Criar experiências onde as tarefas podem ser concluídas de forma rápida e eficiente é crucial para a satisfação do utilizador. As aplicações condicionadas por modelo podem ser altamente personalizadas para criar experiências que atendam às necessidades dos seus utilizadores, mas é importante saber como programar, criar e executar aplicações condicionadas por modelo que são carregadas rapidamente quando um utilizador abre e navega na sua aplicação enquanto trabalha nas tarefas diárias. O desempenho tem mostrado ser um dos principais fatores de insatisfação de uma aplicação quando não está otimizada para o desempenho.

As personalizações inteligentes e os formulários com bom desempenho são aspetos importantes para criar formulários produtivos e altamente eficientes. Também é importante assegurar que está a criar formulários altamente produtivos com as melhores práticas no design e no esquema da interface de utilizador. Para obter informações sobre como criar formulários a pensar na eficiência e na produtividade, consulte Conceber formulários principais produtivos em aplicações condicionadas por modelo.

Também é importante assegurar que os utilizadores estão em dispositivos recomendados e suportados, e com as especificações mínimas exigidas. Mais informações: Browsers e dispositivos móveis suportados

Trabalhar com dados e separadores

Esta secção cobre a forma como os controlos que apresentam dados e separadores afetam o desempenho dos formulários.

Significado do separador predefinido

O separador predefinido é o primeiro separador expandido num formulário. Desempenha um papel especial no carregamento de uma página de formulário. Por conceção, os controlos do separador predefinido são sempre compostos ao abrir um registo. Especificamente, a lógica de inicialização do controlo, como a obtenção de dados, é invocada para cada controlo no separador.

Por outro lado, um separador secundário não executa esta inicialização nos respetivos controlos quando o formulário é carregado inicialmente. Em vez disso, a inicialização do controlo ocorre no momento em que o separador secundário é aberto através da interação do utilizador ou ao chamar o método da API de cliente setFocus. Isto oferece uma oportunidade para proteger o carregamento do formulário inicial contra o processamento de controlo excessivo ao colocar determinados controlos em separadores secundários, em vez de no separador predefinido. Assim, a estratégia de colocação de controlos pode ter um efeito significativo na capacidade de resposta do carregamento inicial do formulário. Um separador com maior capacidade de resposta proporciona uma melhor experiência global para modificar campos importantes, interagir com a barra de comandos, e explorar outros separadores e secções.

Coloque sempre os controlos mais utilizados na parte superior do separador predefinido. A arquitetura de disposição e das informações não é importante apenas para o desempenho, mas também para melhorar a produtividade quando os utilizadores interagem com os dados no formulário. Mais informações: Conceber formulários principais produtivos em aplicações condicionadas por modelo

Controlos orientados por dados

Os controlos que necessitam de dados adicionais para além do registo primário produzem a maior tensão na capacidade de resposta e velocidade de carregamento do formulário. Estes controlos obtêm dados sobre a rede e, muitas vezes, envolvem um período de espera (visto como indicadores de progresso) porque pode demorar algum tempo para transmitir os dados.

Alguns dos controlos orientadas por dados incluem:

Mantenha apenas os controlos mais utilizados no separador predefinido. Os restantes controlos orientados por dados devem ser distribuídos por separadores secundários para permitir o rápido carregamento do separador predefinido. Além disso, esta estratégia de esquema reduz a probabilidade de obter dados que acabam por não ser utilizados.

Existem outros controlos menos impactantes do que os controlos orientados por dados, mas continuam a poder participar na estratégia de esquema acima para obter o melhor desempenho. Estes controlos incluem:

Browser

Esta secção abrange as boas práticas para utilizar os browsers.

Não abrir novas janelas

O método da API de cliente openForm permite que uma opção de parâmetro apresente um formulário numa nova janela. Não utilize este parâmetro ou defina-o como falso. Defini-lo em falso assegurará que o método openForm executa o comportamento predefinido de apresentar o formulário através da janela existente. Também é possível ligar diretamente para a função JavaScript window.open a partir de um script personalizado ou de outra aplicação; no entanto, isto também deve ser evitado. Abrir uma nova janela significa que todos os recursos da página precisam de ser obtidos e carregados de raiz, uma vez que a página é incapaz de tirar partido das funcionalidades de colocação na cache de dados na memória entre um formulário carregado previamente e o formulário numa nova janela. Como alternativa à abertura de novas janelas, considere utilizar a experiência multisessão que permite abrir registos em vários separadores, maximizando ao mesmo tempo as vantagens do desempenho da colocação na cache do cliente.

Utilizar browsers modernos

É fundamental utilizar o browser mais atualizado para assegurar que a sua aplicação condicionada por modelo é executada o mais rapidamente possível. A razão para isto é que muitas das melhorias de desempenho só podem ser utilizadas nos browsers modernos mais recentes.

Por exemplo, se a sua organização tiver versões mais antigas do Firefox, browsers não baseados no Chromium, etc., muitos dos ganhos de desempenho integrados numa aplicação condicionada por modelo não estarão disponíveis nas versões mais antigas do browser porque não suportam funcionalidades das quais a aplicação depende para funcionar de forma rápida e fluida.

Na maioria dos casos, pode esperar ver melhorias no carregamento das páginas com a simples mudança para o Microsoft Edge, ao atualizar para a versão de browser atual mais recente a partir de uma versão mais antiga ou ao mudar para um browser moderno baseado em Chromium.

Personalização do JavaScript

Esta secção cobre como fazer personalizações inteligentes quando utiliza o JavaScript, o que o ajuda criar construir formulários e páginas com bom desempenho numa aplicação condicionada por modelo.

Utilizar JavaScript com formulários

A capacidade de personalizar os formulários com o JavaScript proporciona aos programadores profissionais uma grande flexibilidade em termos de aparência e comportamento de um formulário. O uso inadequado desta flexibilidade pode ter um impacto negativo no desempenho do formulário. Os programadores devem utilizar as seguintes estratégias para maximizar o desempenho do formulário quando implementam personalizações do JavaScript.

Utilizar pedidos de rede assíncronos ao solicitar dados

Solicite os dados de forma assíncrona, e não síncrona, quando são necessários dados adicionais para personalizações. Para os eventos que suportam a espera de código assíncrono, como os eventos OnLoad do formulário e OnSave do formulário, os processadores de eventos devem devolver um Promise para a plataforma aguardar até Promise ser estabelecida. A plataforma mostrará uma IU adequada enquanto o utilizador aguarda pela conclusão do evento.

Para os eventos que não suportam esperar por código assíncrono, como o evento OnChange de formulário, poderá usar uma solução para parar a interação com um formulário enquanto o código está a fazer um pedido assíncrono utilizando showProgressIndicator. Isto é melhor do que utilizar pedidos síncronos porque os utilizadores ainda poderão interagir com outras partes da aplicação à medida que é apresentado um indicador de progresso.

Segue-se um exemplo de utilização de código assíncrono em pontos de extensão síncronos.

//Only do this if an extension point does not yet support asynchronous code
try {
    await Xrm.WebApi.retrieveRecord("settings_entity", "7333e80e-9b0f-49b5-92c8-9b48d621c37c");
    //do other logic with data here
} catch (error) {
    //do other logic with error here
} finally {
    Xrm.Utility.closeProgressIndicator();
}

// Or using .then/.finally
Xrm.Utility.showProgressIndicator("Checking settings...");
Xrm.WebApi.retrieveRecord("settings_entity", "7333e80e-9b0f-49b5-92c8-9b48d621c37c")
    .then(
        (data) => {
            //do other logic with data here
        },
        (error) => {
            //do other logic with error here
        }
    )
    .finally(Xrm.Utility.closeProgressIndicator);

Deverá ter cuidado ao utilizar código assíncrono num processador de eventos que não suporte a espera por código assíncrono. Isto é particularmente verdade para o código que precisa que uma ação seja tomada ou processada na resolução do código assíncrono. O código assíncrono pode causar problemas se o processador de resolução esperar que o contexto da aplicação permaneça o mesmo que era quando o código assíncrono foi iniciado. O seu código deve verificar se o utilizador está no mesmo contexto após cada ponto de continuação assíncrono.

Por exemplo, poderá existir código num processador de eventos para fazer um pedido de rede e alterar um controlo para ser desativado com base nos dados da resposta. Antes de ser recebida a resposta do pedido, o utilizador pode ter interagido com o controlo ou navegado para uma página diferente. Como o utilizador está numa página diferente, o contexto do formulário poderá não estar disponível, o que poderá gerar a erros, ou poderão existir outros comportamentos indesejados.

Suporte assíncrono nos eventos OnLoad de formulário e OnSave de formulário

Os eventos OnLoad e OnSave do formulário suportam processadores que obtêm promessas. Os eventos aguardarão pela resolução de quaisquer promessas devolvidas por um processador, até um período de tempo de espera. Este suporte pode ser ativado através das definições da aplicação.

Mais informações:

Limitar a quantidade de dados pedidos durante o carregamento do formulário

Solicite apenas o volume mínimo de dados necessários para executar lógica de negócio num formulário. Coloque em cache os dados que são solicitados o máximo possível, sobretudo para os dados que não mudam frequentemente ou não precisam de estar atualizados. Por exemplo, imagine que existe um formulário que solicita dados a partir de uma tabela definição. Baseado nos dados na tabela de definições, o formulário poderá optar por ocultar uma secção do formulário. Neste caso, o JavaScript pode colocar dados em cache em sessionStorage para os dados só serem solicitados uma vez por sessão (onLoad1). Também poderá ser utilizada uma estratégia "obsoleto durante a revalidação" quando o JavaScript utilizar os dados a partir de sessionStorage ao pedir dados para a navegação seguinte para o formulário (onLoad2). Finalmente, poderia ser usada uma estratégia de eliminação de duplicados no caso de um processador ser chamado várias vezes seguidas (onLoad3).

const SETTING_ENTITY_NAME = "settings_entity";
const SETTING_FIELD_NAME = "settingField1";
const SETTING_VALUE_SESSION_STORAGE_KEY = `${SETTING_ENTITY_NAME}_${SETTING_FIELD_NAME}`;

// Retrieve setting value once per session
async function onLoad1(executionContext) {
    let settingValue = sessionStorage.getItem(SETTING_VALUE_SESSION_STORAGE_KEY);

    // Ensure there is a stored setting value to use
    if (settingValue === null || settingValue === undefined) {
        settingValue = await requestSettingValue();
    }

    // Do logic with setting value here
}

// Retrieve setting value with stale-while-revalidate strategy
async function onLoad2(executionContext) {
    let settingValue = sessionStorage.getItem(SETTING_VALUE_SESSION_STORAGE_KEY);

    // Revalidate, but only await if session storage value is not present
    const requestPromise = requestSettingValue();

    // Ensure there is a stored setting value to use the first time in a session
    if (settingValue === null || settingValue === undefined) {
        settingValue = await requestPromise;
    }
    
    // Do logic with setting value here
}

// Retrieve setting value with stale-while-revalidate and deduplication strategy
let requestPromise;
async function onLoad3(executionContext) {
    let settingValue = sessionStorage.getItem(SETTING_VALUE_SESSION_STORAGE_KEY);

    // Request setting value again but don't wait on it
    // In case this handler fires twice, don’t make the same request again if it is already in flight
    // Additional logic can be added so that this is done less than once per page
    if (!requestPromise) {
        requestPromise = requestSettingValue().finally(() => {
            requestPromise = undefined;
        });
    }

    // Ensure there is a stored setting value to use the first time in a session
    if (settingValue === null || settingValue === undefined) {
        settingValue = await requestPromise;
    }
    
    // Do logic with setting value here
}

async function requestSettingValue() {
    try {
        const data = await Xrm.WebApi.retrieveRecord(
            SETTING_ENTITY_NAME,
            "7333e80e-9b0f-49b5-92c8-9b48d621c37c",
            `?$select=${SETTING_FIELD_NAME}`);
        try {
            sessionStorage.setItem(SETTING_VALUE_SESSION_STORAGE_KEY, data[SETTING_FIELD_NAME]);
        } catch (error) {
            // Handle sessionStorage error
        } finally {
            return data[SETTING_FIELD_NAME];
        }
    } catch (error) {
        // Handle retrieveRecord error   
    }
}

Utilize as informações disponíveis na API de cliente em vez de fazer pedidos. Por exemplo, em vez de solicitar os direitos de acesso de um utilizador ao carregar o formulário, poderá utilizar getGlobalContext.userSettings.roles.

Carregar código apenas quando for necessário

Carregue todo o código necessário para os eventos para um determinado formulário. Se tiver um código que seja apenas para o formulário A e formulário B, não deve ser incluído numa biblioteca que seja carregada para o formulário C. Devia estar na sua própria biblioteca.

Evite carregar bibliotecas no evento OnLoad se só forem utilizadas apenas para os eventos OnChange ou OnSave. Em vez disso, carregue-nos nesses eventos. Desta forma, a plataforma poderá adiar o carregamento até depois dos carregamentos de formulários. Mais informações: Otimizar o desempenho do formulário

Remover a utilização de APIs de consola no código de produção

Não utilize os métodos de API da consola, como console.log no código de produção. Registar dados na consola pode aumentar significativamente a procura de memória e pode impedir que os dados sejam limpos na memória. Isto pode fazer com que a aplicação se torne mais lenta com o tempo e, eventualmente, falhe.

Evitar fugas de memória

As fugas de memória no seu código podem levar a um desempenho mais lento ao longo do tempo e, eventualmente, causar a falha da sua aplicação. As fugas de memória ocorrem quando a aplicação não liberta memória quando já não é necessária. Com todas as personalizações e componentes de código no seu formulário, deve:

  • Considerar minuciosamente e testar cenários para qualquer coisa responsável pela limpeza da memória, como classes responsáveis pela gestão do ciclo de vida de objetos.
  • Limpeza de todos os serviços de escuta e subscrições do evento, especialmente se estiver no objeto window.
  • Limpar todos os temporizadores, como setInterval.
  • Evite, limite e limpe referências a objetos globais ou estáticos.

Para componentes de controlo personalizado, a limpeza pode ser feita no método de destruir.

Para obter mais informações sobre a correção de problemas de memória, aceda a esta documentação do programador do Edge.

Ferramentas que pode utilizar para ajudar a melhorar o desempenho das aplicações

Esta secção descreve as ferramentas que podem ajudá-lo a compreender os problemas de desempenho e a oferecer recomendações sobre como otimizar as suas personalizações em aplicações condicionadas por modelo.

Informações de desempenho

Os insights de desempenho são uma ferramenta self-service para os criadores de aplicações empresariais que analisam dados de telemetria em runtime e fornece uma lista de recomendações com prioridades para ajudar a melhorar o desempenho das aplicações condicionadas por modelo. Esta funcionalidade fornece um conjunto diário de informações analíticas relacionadas com o desempenho de uma aplicação do Power Apps condicionada por modelos ou de Customer engagement, como o Dynamics 365 Sales ou Dynamics 365 Service, com recomendações e itens acionáveis. Os criadores de aplicações da empresa podem ver insights de desempenho detalhados a nível da aplicação no Power Apps. Mais informações: O que são insights de desempenho? (pré-visualização)

Verificador de soluções

O verificador de soluções é uma potente ferramenta que pode analisar personalizações de clientes e servidores para problemas de desempenho ou fiabilidade. Pode analisar o JavaScript do lado do cliente, o XML do formulário e os plug-ins do lado do servidor .NET, e fornecer insights direcionados sobre o que pode tornar os utilizadores finais mais lentos. Recomendamos que execute verificadores de soluções sempre que publique alterações num ambiente de desenvolvimento para quaisquer preocupações de desempenho serem detetadas antes de chegarem aos utilizadores finais. Mais informações: Utilize o verificador de soluções para validar as aplicações condicionadas por modelo no Power Apps

Alguns exemplos de problemas relacionados com o desempenho encontrados com o verificador de soluções:

Verificador de objetos

O verificador de objetos executa diagnósticos em tempo real em objetos componentes dentro da sua solução. Se forem detetados problemas, é devolvida uma recomendação que descreve como corrigir o problema. Mais informações: Utilizar o verificador de objetos para diagnosticar um componente da solução (pré-visualização)

Passos seguintes

Estruturar formulários principais produtivos em aplicações condicionadas por modelo