Formulários de design para desempenho em aplicativos baseados em modelo

Criar experiências em que as tarefas podem ser concluídas de forma rápida e eficiente é crucial para a satisfação do usuário. Aplicativos baseados em modelo podem ser altamente personalizados para criar experiências que atendam às necessidades dos usuários, mas é importante saber efetivamente como codificar, criar e executar aplicativos baseados em modelo que são carregados rapidamente quando um usuário abre e navega em seu aplicativo enquanto trabalha em tarefas diárias. O desempenho tem demonstrado ser um fator importante de insatisfação com um aplicativo quando ele não está otimizado para desempenho.

Personalizações inteligentes e formulários de desempenho são aspectos importantes para a criação de formulários altamente eficientes e produtivos. Também é importante certificar-se de que você está criando formulários altamente produtivos com as melhores práticas de design e layout de interface de usuário. Para obter informações sobre como projetar formulários para eficiência e produtividade, consulte Projetar formulários principais produtivos em aplicativos baseados em modelo.

Também é importante garantir que os usuários usem os dispositivos recomendados e compatíveis e as especificações mínimas exigidas. Mais informações: Navegadores da Web e dispositivos móveis compatíveis

Trabalhar com os dados e guias

Esta seção aborda como os controles que exibem dados e guias afetam o desempenho do formulário.

Significado da guia padrão

A guia padrão é a primeira guia expandida em um formulário. Ela desempenha um papel especial no carregamento de uma página de formulário. Por design, os controles da guia padrão são sempre renderizados ao abrir um registro. Especificamente, a lógica de inicialização do controle, como recuperação de dados, é chamada para cada controle na guia.

Por outro lado, uma guia secundária não executa essa inicialização nos controles quando o formulário é inicialmente carregado. Em vez disso, a inicialização do controle ocorre no momento em que a guia secundária é aberta por meio da interação do usuário ou chamando o método de API do cliente setFocus. Isso fornece uma oportunidade de proteger o carregamento inicial do formulário do processamento excessivo de controles, colocando certos controles em guias secundárias em vez da guia padrão. Assim, a estratégia de posicionamento de controles pode ter um efeito significativo na capacidade de resposta do carregamento inicial do formulário. Uma guia padrão mais responsiva fornece uma experiência geral melhor para modificar campos importantes, interagir com a barra de comandos e explorar outras guias e seções.

Sempre coloque os controles mais usados na parte superior da guia padrão. O layout e a arquitetura de informações não são importantes apenas para o desempenho, mas também para melhorar a produtividade quando os usuários interagem com os dados no formulário. Mais Informações: Projetar formulários principais produtivos em aplicativos baseados em modelo

Controles baseados em dados

Os controles que exigem dados extras além do registro principal produzem tensão máxima na capacidade de resposta do formulário e na velocidade de carregamento. Esses controles buscam dados na rede e geralmente envolvem um período de espera (visto como indicadores de progresso) porque pode demorar para transmitir os dados.

Alguns dos controles baseados em dados incluem:

Mantenha apenas os controles usados com mais frequência na guia padrão. Os demais controles baseados em dados devem ser distribuídos em guias secundárias para permitir que a guia padrão seja carregada rapidamente. Além disso, essa estratégia de layout reduz a chance de buscar dados que acabam não sendo usados.

Existem outros controles que são menos impactantes do que os controles baseados em dados, mas ainda podem participar da estratégia de layout acima para obter o melhor desempenho. Esses controles incluem:

Navegador da Web

Esta seção aborda as boas práticas para uso com navegadores da Web.

Não abra novas janelas

O método de API do cliente openForm permite uma opção de parâmetro para exibir um formulário em uma nova janela. Não use esse parâmetro ou o defina como falso. A definição como falso garantirá que o método openForm execute o comportamento padrão de exibir o formulário usando a janela existente. Também é possível chamar diretamente a função JavaScript window.open de um script personalizado ou de outro aplicativo. No entanto, isso também deve ser evitado. Abrir uma nova janela significa que todos os recursos da página precisam ser buscados e carregados do zero, uma vez que a página é incapaz de aproveitar os recursos de cache de dados na memória entre um formulário carregado anteriormente e o formulário em uma nova janela. Como alternativa à abertura de novas janelas, considere usar a experiência multissessão. Ela permite que os registros sejam abertos em várias guias enquanto maximiza os benefícios de desempenho do armazenamento em cache do cliente.

Usar navegadores modernos

Usar o navegador da Web mais atualizado é fundamental para garantir que seu aplicativo baseado em modelo seja executado o mais rápido possível. A razão para isso é que muitas das melhorias de desempenho só podem ser usadas nos navegadores modernos mais recentes.

Por exemplo, se a sua organização tiver versões mais antigas do Firefox, navegadores não baseados em Chromium e assim por diante, muitos dos ganhos de desempenho que são integrados em um aplicativo baseado em modelo não estarão disponíveis nas versões mais antigas do navegador porque eles não são compatíveis com os recursos que o aplicativo precisa para ser executado rapidamente e sem problemas.

Na maioria dos casos, você pode esperar ver melhorias no carregamento da página apenas mudando para o Microsoft Edge, atualizando para a versão atual mais recente do navegador ou mudando para um navegador moderno baseado em Chromium.

Personalização do JavaScript

Esta seção explica como fazer personalizações inteligentes ao usar JavaScript, que ajudam você a criar formulários e páginas de alto desempenho em um aplicativo orientado a modelo.

Usar JavaScript com formulários

A capacidade de personalizar formulários usando JavaScript fornece aos desenvolvedores profissionais grande flexibilidade na aparência e no comportamento de um formulário. O uso impróprio dessa flexibilidade pode afetar negativamente o desempenho do formulário. Os desenvolvedores devem usar as seguintes estratégias para maximizar o desempenho do formulário ao implementar personalizações de JavaScript.

Usar solicitações de rede assíncronas ao solicitar dados

Solicitar dados de maneira assíncrona, em vez de síncrona, quando dados extras forem necessários para personalizações. Para eventos compatíveis com espera por código assíncrono, como os eventos dos formulários OnLoad e OnSave, os manipuladores de eventos devem retornar um Promise para que a plataforma espere até que o Promise seja resolvido. A plataforma mostrará uma IU apropriada enquanto o usuário espera a conclusão do evento.

Para eventos não compatíveis com espera por código assíncrono, como o evento do formulário OnChange, você pode usar uma solução alternativa para interromper a interação com um formulário enquanto o código está fazendo uma solicitação assíncrona usando showProgressIndicator. Isso é melhor do que usar solicitações síncronas porque os usuários ainda poderão interagir com outras partes do aplicativo conforme um indicador de progresso é exibido.

Veja um exemplo 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);

Você deve ter cuidado ao usar código assíncrono em um manipulador de eventos que não é compatível com a espera por código assíncrono. Isso é particularmente verdadeiro para o código que precisa que uma ação seja executada ou tratada na resolução do código assíncrono. O código assíncrono pode causar problemas se o manipulador de resolução esperar que o contexto do aplicativo permaneça o mesmo de quando o código assíncrono foi iniciado. Seu código deve verificar se o usuário está no mesmo contexto após cada ponto de continuação assíncrono.

Por exemplo, pode haver código em um manipulador de eventos para fazer uma solicitação de rede e desabilitar um controle com base nos dados de resposta. Antes que a resposta da solicitação seja recebida, o usuário pode ter interagido com o controle ou navegado para uma página diferente. Como o usuário está em uma página diferente, talvez o contexto do formulário não esteja disponível, o que pode levar a erros, ou pode haver outro comportamento indesejado.

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

Os eventos OnLoad e OnSave do formulário dão suporte a manipuladores que retornam promessas. Os eventos esperam qualquer promessa retornada por um manipulador para resolver, até um determinado tempo limite. Esse suporte pode ser habilitado pelas configurações do aplicativo.

Mais informações:

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

Solicite apenas a quantidade mínima de dados necessária para executar a lógica de negócios em um formulário. Armazene em cache os dados solicitados tanto quanto possível, especialmente para dados que não mudam com frequência ou não precisam ser atualizados. Por exemplo, imagine que existe um formulário que solicita dados de uma tabela de configuração. Com base nos dados da tabela de configuração, o formulário pode optar por ocultar uma seção dele. Nesse caso, o JavaScript pode armazenar dados em cache em sessionStorage para que os dados sejam solicitados apenas uma vez por sessão (onLoad1). Uma estratégia antiga durante a revalidação também pode ser usada quando o JavaScript usa os dados de sessionStorage ao solicitar dados para a próxima navegação no formulário (onLoad2). Por fim, uma estratégia de desduplicação pode ser usada no caso de um manipulador 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   
    }
}

Use as informações disponíveis na API do cliente em vez de fazer solicitações. Por exemplo, em vez de solicitar os direitos de acesso de um usuário no carregamento do formulário, você pode usar getGlobalContext.userSettings.roles.

Carregar o código apenas quando necessário

Carregue tanto código quanto necessário para eventos de um formulário específico. Se você tiver um código que seja apenas para formulário A e formulário B, ele não deverá ser incluído em uma biblioteca carregada para formulário C. Ele deve estar em sua própria biblioteca.

Evite carregar bibliotecas no evento OnLoad se elas forem usadas apenas para o eventos OnChange ou OnSave. Em vez disso, carregue-as nesses eventos. Desta forma, a plataforma pode adiar o carregamento até depois do carregamento do formulário. Mais Informações: Otimizar o desempenho do formulário

Remover o uso de APIs de console no código de produção

Não use os métodos da API de console tal como console.log no código de produção. O registro de dados no console pode aumentar significativamente a demanda de memória e pode impedir que os dados sejam limpos na memória. Isso pode fazer com que o aplicativo fique mais lento com o tempo e, eventualmente, falhe.

Evitar vazamentos de memória

Vazamentos de memória em seu código podem levar a um desempenho mais lento ao longo do tempo e, mais cedo ou mais tarde, fazer com que o aplicativo falhe. Vazamentos de memória ocorrem quando o aplicativo não libera memória quando não é mais necessário. Com todas as personalizações e componentes de código em seu formulário, você deve:

  • Considerar e testar minuciosamente os cenários para tudo que for responsável por limpar a memória, como classes responsáveis por gerenciar o ciclo de vida de objetos.
  • Limpar todos os ouvintes e assinaturas de evento, especificamente se estiverem no objeto window.
  • Limpar todos os temporizadores, como setInterval.
  • Evitar, limitar e limpar referências para objetos globais ou estáticos.

Para componentes de controle personalizados, a limpeza pode ser feita no método destroy.

Para obter mais informações sobre como corrigir problemas de memória, acesse esta documentação do desenvolvedor do Edge.

Ferramentas que você pode usar para ajudar a tornar os aplicativos eficientes

Esta seção descreve as ferramentas que podem ajudar você a entender os problemas de desempenho e oferece recomendações sobre como otimizar suas personalizações em aplicativos baseados em modelo.

Insights de desempenho

Insights de desempenho é uma ferramenta de autoatendimento para criadores de apps empresariais que analisa dados de telemetria em runtime e fornece uma lista priorizada de recomendações para ajudar a melhorar o desempenho de aplicativos baseados em modelo. Este recurso fornece um conjunto diário de insights analíticos relacionados ao desempenho de um aplicativo baseado em modelo ou de engajamento do cliente do Power Apps, como o Dynamics 365 Sales ou o Dynamics 365 Service, com recomendações e itens acionáveis. Os criadores de apps empresariais podem exibir insights de desempenho detalhados no nível do aplicativo no Power Apps. Mais Informações: O que são insights de desempenho? (versão preliminar)

Verificador de solução

O verificador de solução é uma ferramenta poderosa que pode analisar personalizações de cliente e servidor em busca de problemas de desempenho ou confiabilidade. Ele pode analisar JavaScript do cliente, formulário XML e plug-ins .NET do servidor e fornecer insights direcionados sobre o que pode atrasar os usuários finais. Recomendamos que você execute o verificador de solução cada vez que publicar alterações em um ambiente de desenvolvimento, para que qualquer preocupação com o desempenho seja levantada antes de chegar aos usuários finais. Mais informações: Usar o verificador de soluções para validar seus aplicativos baseados em modelos no Power Apps

Alguns exemplos de problemas relacionados ao desempenho encontrados com o verificador de solução:

Verificador de objeto

O verificador de objetos executa diagnósticos em tempo real em objetos de componentes em sua solução. Se forem detectados problemas, uma recomendação será retornada com a descrição de como corrigir o problema. Mais informações: Usar o verificador de objetos para diagnosticar um componente da solução (versão preliminar)

Próximas etapas

Criar formulários principais produtivos em aplicativos baseados em modelos