Projektowanie formularzy wydajności w aplikacjach opartych na modelu

Budowanie doświadczeń, w których zadania mogą być wykonywane szybko i sprawnie, jest kluczowe dla satysfakcji użytkowników. Aplikacje sterowane modelami mogą być w dużym stopniu dostosowane do potrzeb użytkowników, ale ważne jest, aby wiedzieć, jak skutecznie kodować, budować i uruchamiać aplikacje sterowane modelami, które ładują się szybko, gdy użytkownik otwiera i nawiguje w aplikacji podczas pracy nad codziennymi zadaniami. Wykazano, że wydajność jest kluczowym czynnikiem powodującym niezadowolenie z aplikacji, jeśli nie jest ona zoptymalizowana pod kątem wydajności.

Inteligentne dostosowanie i wydajne formularze są ważnymi aspektami w budowaniu wysoce wydajnych i produktywnych formularzy. Ważne jest również, aby upewnić się, że budujesz wysoce wydajne formularze z najlepszymi praktykami w projektowaniu interfejsu użytkownika i układu. Aby uzyskać informacje na temat projektowania formularzy pod kątem wydajności i produktywności, zobacz Projektowanie produktywnych formularzy głównych w aplikacjach sterowanych modelami.

Ważne jest również, aby upewnić się, że użytkownicy korzystają z zalecanych i obsługiwanych urządzeń oraz minimalnych wymaganych specyfikacji. Więcej informacji: Obsługiwane przeglądarki internetowe i urządzenia mobilne

Praca z danymi liczbowymi i kartami

W tej sekcji opisano sposób, w jaki formanty wyświetlają dane i karty, które mają wpływ na wydajność formularza.

Znaczenie karty domyślnej

Domyślna zakładka jest pierwszą rozwiniętą zakładką na formularzu. Odgrywa on szczególną rolę w ładowaniu strony formularza. Z założenia kontrolki domyślnej zakładki są zawsze wyświetlane podczas otwierania rekordu. W szczególności, logika inicjalizacji kontrolki, taka jak pobieranie danych, jest wywoływana dla każdej kontrolki na karcie.

W przeciwieństwie do tego, drugorzędna karta nie wykonuje tej inicjalizacji na swoich kontrolkach, gdy formularz jest początkowo ładowany. Zamiast tego, inicjalizacja kontroli następuje w momencie otwarcia dodatkowej zakładki poprzez interakcję użytkownika lub wywołanie metody API klienta setFocus. Daje to możliwość ochrony początkowego obciążenia formularza przed nadmiernym przetwarzaniem kontrolek poprzez umieszczenie niektórych kontrolek w drugorzędnych zakładkach zamiast w zakładce domyślnej. W ten sposób strategia rozmieszczania kontrolek może mieć znaczący wpływ na responsywność początkowego obciążenia formularza. Bardziej responsywna karta domyślna zapewnia lepsze ogólne wrażenia podczas modyfikowania ważnych pól, interakcji z paskiem poleceń oraz poznawania innych kart i sekcji.

Zawsze umieszczaj kontrolki, które są najczęściej używane na górze domyślnej zakładki. Układ i architektura informacji są ważne nie tylko ze względu na wydajność, ale także w celu poprawy produktywności, gdy użytkownicy wchodzą w interakcję z danymi na formularzu. Więcej informacji: Projektowanie produktywnych form głównych w aplikacjach opartych na modelu

Formanty oparte na danych

Kontrolki, które wymagają dodatkowych danych poza rekordem głównym, powodują największe obciążenie responsywności formularza i szybkości ładowania. Te elementy sterujące pobierają dane za pośrednictwem sieci i często wiążą się z okresem oczekiwania (widocznym jako wskaźniki postępu), ponieważ przesyłanie danych może zająć trochę czasu.

Niektóre formanty oparte na danych to:

Na domyślnej zakładce powinny znajdować się tylko najczęściej używane kontrolki. Pozostałe kontrolki oparte na danych powinny być rozmieszczone na drugorzędnych zakładkach, aby umożliwić szybkie ładowanie domyślnej zakładki. Ponadto, ta strategia układu zmniejsza szansę na pobranie danych, które kończą się niewykorzystane.

Istnieją inne elementy sterujące, które mają mniejszy wpływ niż elementy sterujące oparte na danych, ale nadal mogą uczestniczyć w powyższej strategii układu w celu osiągnięcia najlepszej wydajności. Do tych formantów należą:

Przeglądarka sieci Web

W tej sekcji omówiono dobre praktyki, które należy stosować w przeglądarkach internetowych.

Nie otwieraj nowych okien

Metoda API klienta openForm umożliwia za pomocą parametru opcję wyświetlenia formularza w nowym oknie. Nie należy używać tego parametru ani ustawiać go jako false. Ustawienie jej na false spowoduje, że metoda openForm wykona domyślne zachowanie polegające na wyświetleniu formularza przy użyciu istniejącego okna. Możliwe jest również bezpośrednie wywołanie funkcji JavaScript window.open z własnego skryptu lub innej aplikacji; jednakże, to również powinno być unikane. Otwarcie nowego okna oznacza, że wszystkie zasoby strony muszą zostać pobrane i załadowane od nowa, ponieważ strona nie jest w stanie wykorzystać możliwości buforowania danych w pamięci pomiędzy wcześniej załadowanym formularzem a formularzem w nowym oknie. Jako alternatywę do otwierania nowych okien, rozważ użycie doświadczenia multisesyjnego, które pozwala na otwieranie rekordów w wielu kartach, jednocześnie maksymalizując korzyści z wydajności buforowania klienta.

Użyj nowoczesnych przeglądarek

Używanie najbardziej aktualnej przeglądarki internetowej jest kluczem do zapewnienia, że Twoja aplikacja oparta na modelu działa tak szybko, jak to tylko możliwe. Powodem tego jest fakt, że wiele z ulepszeń wydajności może być wykorzystanych tylko w nowszych, nowoczesnych przeglądarkach.

Na przykład, jeśli Twoja organizacja posiada starsze wersje przeglądarki Firefox, przeglądarki nie oparte na chromie, itd., wiele korzyści związanych z poprawą wydajności, które są wbudowane w aplikacje oparte na modelu, nie będą dostępne w starszych wersjach przeglądarek, ponieważ nie obsługują one funkcji, od których zależy szybkie i płynne działanie aplikacji.

W większości przypadków możesz spodziewać się poprawy ładowania stron po prostu przechodząc na Microsoft Edge, aktualizując do najnowszej aktualnej wersji przeglądarki ze starszej wersji lub przechodząc na nowoczesną przeglądarkę opartą na Chromium.

Dostosowywanie języka JavaScript

Ta sekcja omawia, jak dokonać inteligentnych dostosowań podczas używania JavaScriptu, które pomagają budować wydajne formularze i strony w aplikacji opartej na modelu.

Korzystanie z języka JavaScript w formularzach

Możliwość dostosowywania formularzy przez JavaScript zapewnia profesjonalnym programistom dużą elastyczność w zakresie wyglądu i zachowania formularza. Niewłaściwe wykorzystanie tej elastyczności może negatywnie wpłynąć na wydajność formy. Programiści powinni używać poniższych strategii, aby zmaksymalizować wydajność formularzy podczas implementacji dostosowań JavaScript.

Żądania sieci asynchroniczne podczas żądania danych

Żądaj danych asynchronicznie zamiast synchronicznie, gdy dodatkowe dane są niezbędne do dostosowania. Dla zdarzeń, które wspierają oczekiwanie na kod asynchroniczny jak formularz OnLoad i formularz OnSave, obsługa zdarzeń powinna zwracać Promise, aby platforma czekała aż Promise zostanie rozliczona. Platforma wyświetli odpowiedni UI, podczas gdy użytkownik będzie oczekiwał na zakończenie zdarzenia.

Dla zdarzeń, które nie obsługują czekania na kod asynchroniczny, jak np. zdarzenie OnChange, można użyć obejścia, aby zatrzymać interakcję z formularzem, podczas gdy kod wykonuje żądanie asynchroniczne za pomocą showProgressIndicator. Jest to lepsze rozwiązanie niż używanie żądań synchronicznych, ponieważ użytkownicy nadal będą mogli wchodzić w interakcje z innymi częściami aplikacji, gdy wyświetlany jest wskaźnik postępu.

Oto przykład użycia asynchronicznego kodu w synchronicznych punktach rozszerzeń.

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

Powinieneś być ostrożny podczas używania kodu asynchronicznego w obsłudze zdarzeń, która nie obsługuje oczekiwania na kod asynchroniczny. Jest to szczególnie prawdziwe w przypadku kodu, który wymaga akcji, która ma zostać podjęta lub obsłużona po rozwiązaniu kodu asynchronicznego. Kod asynchroniczny może powodować problemy, jeśli obsługa rozdzielczości oczekuje, że kontekst aplikacji pozostanie taki sam, jak w momencie uruchomienia kodu asynchronicznego. Twój kod powinien sprawdzić, czy użytkownik znajduje się w tym samym kontekście po każdym asynchronicznym punkcie kontynuacji.

Na przykład, w programie obsługi zdarzeń może znajdować się kod do wykonania żądania sieciowego i zmiany kontrolki na wyłączoną w oparciu o dane odpowiedzi. Zanim zostanie odebrana odpowiedź na żądanie, użytkownik mógł wejść w interakcję z kontrolką lub przejść na inną stronę. Ponieważ użytkownik znajduje się na innej stronie, kontekst formularza może nie być dostępny, co może prowadzić do błędów, lub może wystąpić inne niepożądane zachowanie.

Obsługa asynchroniczności w zdarzeniach OnLoad i OnSave formularza

Zdarzenia OnLoad i OnSave formularzy obsługują programy do obsługi, które zwracają obietnice. Zdarzenia będą czekać na rozwiązanie obietnic zwróconych przez handler, aż do momentu przekroczenia limitu czasu. Tę pomoc techniczną można włączyć, korzystając z ustawień aplikacji.

Więcej informacji:

Ograniczenie ilości danych wymaganych podczas ładowania formularza

Żądaj tylko minimalnej ilości danych, która jest niezbędna do wykonania logiki biznesowej na formularzu. Buforuj dane, które są wymagane tak bardzo jak to możliwe, szczególnie dla danych, które nie zmieniają się często lub nie muszą być świeże. Na przykład, wyobraź sobie, że istnieje formularz, który żąda danych z tabeli setting. Na podstawie danych w tabeli ustawień, formularz może zdecydować o ukryciu części formularza. W tym przypadku, JavaScript może buforować dane w sessionStorage tak, że dane są wymagane tylko raz na sesję (onLoad1). Strategia stale-while-revalidate może być również użyta, gdzie JavaScript używa danych z sessionStorage podczas żądania danych dla następnej nawigacji do formularza (onLoad2). Wreszcie, strategia deduplikacji może być użyta w przypadku, gdy handler jest wywoływany wiele razy z rzędu (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   
    }
}

Korzystaj z informacji dostępnych w API klienta, zamiast wykonywać żądania. Na przykład, zamiast żądać ról bezpieczeństwa użytkownika podczas ładowania formularza, możesz użyć getGlobalContext.userSettings.roles.

Załaduj kod tylko wtedy, gdy jest potrzebny

Załaduj tyle kodu, ile jest potrzebnych do zdarzeń dla konkretnego formularza. Jeśli masz kod, który jest tylko dla formularz A i formularz B, nie powinien on być zawarty w bibliotece, która jest ładowana dla formularza C. Powinien być w swojej własnej bibliotece.

Unikaj ładowania bibliotek w zdarzeniu OnLoad jeśli są one używane tylko dla zdarzeń OnChange lub OnSave. Zamiast tego należy załadować je w tych zdarzeniach. W ten sposób platforma może odroczyć ich załadowanie do czasu, gdy formularz się załaduje. Więcej informacji: Optymalizowanie wydajności formularza

Usuwanie użycia interfejsów API konsoli w kodzie produkcyjnym

Nie należy używać metod interfejsu API konsoli, takich jak console.log w kodzie produkcyjnym. Rejestrowanie danych w konsoli może znacznie zwiększyć zapotrzebowanie na pamięć i może uniemożliwić czyszczenie danych w pamięci. Może to z czasem spowodować spowolnienie aplikacji, a nawet jej awarię.

Unikanie wycieków pamięci

Wycieki pamięci w kodzie mogą spowodować za czasem wolniejszą wydajność i w końcu przyczynić się do awarii aplikacji. Wycieki pamięci pojawiają się, gdy aplikacja nie zwolni niepotrzebnej już pamięci. Dla wszystkich dostosowań i składników kodu w formularzu należy:

  • Rozważyć i dokładnie przetestować scenariusze dotyczące wszystkich obiektów odpowiedzialnych za czyszczenie pamięci, na przykład klas odpowiedzialnych za zarządzanie cyklem życia obiektów.
  • Wyczyść wszystkie odbiorniki zdarzeń i subskrypcje, zwłaszcza jeśli są w obiekcie window.
  • Oczyszczanie wszystkich czasomierzy, takich jak setInterval.
  • Należy unikać i wyczyścić odwołania do obiektów globalnych lub statycznych.

W przypadku niestandardowych składników kontrolek oczyszczania można dokonać tylko za pomocą metody zniszczenia.

Aby uzyskać więcej informacji na temat rozwiązywania problemów z pamięcią, przejdź do tej dokumentacji dla deweloperów Edge.

Narzędzia pomocne przy obsłudze aplikacji

Ta sekcja opisuje narzędzia, które mogą pomóc zrozumieć problemy z wydajnością i zaoferować zalecenia dotyczące optymalizacji dostosowań w aplikacjach sterowanych modelami.

Wyniki analiz wydajności

Performance Insights to samoobsługowe narzędzie dla twórców aplikacji korporacyjnych, które analizuje dane telemetryczne i dostarcza listę priorytetowych zaleceń mających na celu poprawę wydajności aplikacji opartych na modelu. Ta funkcja zapewnia codzienny zestaw szczegółowych informacji analitycznych związanych z wydajnością aplikacji Power Apps opartej na modelach lub aplikacji angażującej klientów, takiej jak Dynamics 365 Sales lub Dynamics 365 Service, wraz z rekomendacjami i elementami, które można podjąć. Twórcy aplikacji dla przedsiębiorstw mogą przeglądać szczegółowe informacje na temat wydajności na poziomie aplikacji w Power Apps. Więcej informacji: Co to są informacje na temat wydajności? (wersja zapoznawcza)

Kontroler rozwiązań

Kontroler rozwiązań jest potężnym narzędziem, które może analizować dostosowanie klienta i serwera pod kątem wydajności lub problemów z niezawodnością. Może on analizować JavaScript po stronie klienta, XML formularzy i wtyczki .NET po stronie serwera oraz zapewniać ukierunkowany wgląd w to, co może spowalniać użytkowników końcowych. Zalecamy, aby uruchamiać kontroler rozwiązań za każdym razem, gdy publikujesz zmiany w środowisku deweloperskim, aby wszelkie problemy z wydajnością zostały ujawnione zanim trafią do użytkowników końcowych. Więcej informacji: Użyj modułu sprawdzania rozwiązań do sprawdzania poprawności aplikacji opartych na modelu w Power Apps

Przykłady problemów związanych z wydajnością, które można znaleźć przy użyciu kontrolera rozwiązań:

  • il-specify-column. Należy unikać zaznaczania wszystkich kolumn za pomocą interfejsów API zapytań Dataverse.
  • web-use-async. Wchodź w interakcję z zasobami HTTP i HTTPS asynchronicznie.
  • web-avoid-ui-refreshribbon. Unikaj używania refreshRibbon w formularzach OnLoad i EnableRule.

Kontroler obiektów

Narzędzie do sprawdzania obiektów uruchamia diagnostykę w czasie rzeczywistym obiektów składowych w Twoim rozwiązaniu. W przypadku wykrycia problemów zwracane jest zalecenie opisujące sposób rozwiązania problemu. Więcej informacji: używanie kontrolera obiektów do diagnozowania składnika rozwiązania (wersja zapoznawcza)

Następne kroki

Projektuj produktywne główne formularze w aplikacjach opartych na modelach