Návrhy formulářů orientovaných na výkon v modelem řízených aplikacích

Klíčem ke spokojenosti uživatelů je vytváření prostředí, ve kterých lze úkoly plnit rychle a efektivně. Modelem řízené aplikace lze přizpůsobit tak, aby vytvářely prostředí splňující potřeby vašich uživatelů, ale je důležité vědět, jak efektivně kódovat, vytvářet a spouštět modelem řízené aplikace, které se rychle načtou, když je uživatel ve vaší aplikaci při práci na každodenních úkolech otevře. Ukázalo se, že výkon je klíčovým hnacím motorem nespokojenosti s aplikací, pokud není patřičně optimalizována.

Inteligentní přizpůsobení a výkonné formuláře jsou důležitými aspekty při vytváření vysoce efektivních a produktivních formulářů. Je také důležité zajistit, abyste vytvářeli vysoce produktivní formuláře s využitím osvědčených postupů při návrhu a rozložení uživatelského rozhraní. Informace o navrhování formulářů s důrazem na efektivitu a produktivitu najdete v tématu Návrh produktivních hlavních formulářů v modelem řízených aplikacích.

Je také důležité zajistit, aby uživatelé používali doporučená a podporovaná zařízení splňující minimální požadované specifikace. Další informace: Podporované webové prohlížeče a mobilní zařízení

Práce s daty a kartami

Tato část popisuje, jak výkonnost formuláře ovlivňují ovládací prvky, které zobrazují data a karty.

Význam výchozí karty

Výchozí karta je první rozbalená karta ve formuláři. Hraje zvláštní roli při načítání stránky formuláře. Ve výchozím nastavení se ovládací prvky výchozí karty vždy vykreslí při otevírání záznamu. Logika inicializace ovládacího prvku, jako je načítání dat, je vyvolána pro každý ovládací prvek na kartě.

Oproti tomu sekundární karta při počátečním načtení formuláře neprovádí tuto inicializaci svých ovládacích prvků. Místo toho dojde k inicializaci ovládacího prvku v okamžiku otevření sekundární karty, a to buď prostřednictvím interakce uživatele nebo voláním metody setFocus klientského API. Takto je počáteční načítání formuláře chráněno před nadměrným zpracováním ovládacích prvků, kdy jsou určité ovládací prvky umístěny na sekundární kartu místo na výchozí. Strategie umístění ovládacího prvku tedy může mít významný vliv na rychlost počátečního načtení formuláře. Výchozí karta s rychlejší reakcí poskytuje lepší prostředí pro úpravu důležitých polí, interakce s panelem příkazů a zkoumání dalších karet a sekcí.

Do horní části výchozí karty vždy umístěte ovládací prvky, které se používají nejvíce. Rozložení a informační architektura nejsou důležité pouze z hlediska výkonu, ale také pro zvýšení produktivity, když uživatelé interagují s daty ve formuláři. Více informací: Návrh produktivních hlavních formulářů v modelem řízených aplikacích

Ovládací prvky řízené daty

Ovládací prvky, které vyžadují další data mimo primární záznam, kladou největší nároky na odezvu formuláře a rychlost načítání. Tyto ovládací prvky načítají data přes síť a často zahrnují čekací dobu (zobrazenou jako indikátory průběhu), protože přenos dat může nějakou dobu trvat.

Mezi některé ovládací prvky řízené daty patří:

Na výchozí kartě ponechejte pouze nejčastěji používané ovládací prvky. Zbývající ovládací prvky řízené daty by měly být umístěny na sekundární karty, aby bylo možné rychle načíst výchozí kartu. Tato strategie rozložení navíc snižuje pravděpodobnost zbytečného načítání dat, která nebudou použita.

Existují další ovládací prvky, které mají menší výkonový dopad než ovládací prvky řízené daty, ale přesto se mohou podílet na výše uvedené strategii rozvržení, aby přispěly k co nejvyššímu výkonu. Mezi tyto ovládací prvky patří:

Webový prohlížeč

Tato část popisuje osvědčené postupy pro použití ve webových prohlížečích.

Neotvírat nová okna

Metoda openForm klientského rozhraní API má parametr pro zobrazení formuláře v novém okně. Tento parametr nepoužívejte ani jej nenastavujte na hodnotu false. Nastavením na hodnotu false zajistíte, že metoda openForm provede výchozí chování zobrazení formuláře pomocí existujícího okna. Je také možné přímo zavolat funkci window.open jazyka JavaScript z vlastního skriptu nebo jiné aplikace; tomu by se však také mělo zabránit. Otevření nového okna znamená, že všechny zdroje stránky je třeba načíst od začátku, protože stránka nemůže využívat schopnosti ukládání do mezipaměti dat v paměti mezi dříve načteným formulářem a formulářem v novém okně. Jako alternativu k otevírání nových oken zvažte použití prostředí vícenásobné relace, které umožňuje otevírání záznamů na více kartách při maximalizaci výhod výkonu ukládání do mezipaměti klienta.

Používejte moderní prohlížeče

Používání nejaktuálnějšího webového prohlížeče je klíčem k zajištění toho, aby vaše modelem řízená aplikace běžela co nejrychleji. Důvodem je to, že mnoho vylepšení výkonu lze použít pouze v novějších moderních prohlížečích.

Pokud má vaše organizace například starší verze prohlížeče Firefox, které nejsou založeny na jádru Chromium atp., mnoho zisků v oblasti výkonu, které jsou integrovány do modelem řízené aplikace, nebude ve starších verzích prohlížeče k dispozici, protože tyto verze nepodporují funkce umožňující rychlé a bezproblémové spuštění aplikace.

Ve většině případů můžete očekávat zrychlené načítání stránky pouhým přechodem na prohlížeč Microsoft Edge, aktualizací na nejnovější aktuální verzi prohlížeče ze starší verze nebo přechodem na moderní prohlížeč založený na jádru Chromium.

Přizpůsobení jazyka JavaScript

Tato část popisuje, jak provádět inteligentní přizpůsobení pomocí jazyka JavaScript, který vám pomůže vytvářet výkonné formuláře a stránky v modelem řízené aplikaci.

Použití jazyka JavaScript ve formulářích

Možnost přizpůsobení formulářů pomocí kódu jazyka JavaScript poskytuje profesionálním vývojářům velkou flexibilitu v tom, jak formulář vypadá a jak se chová. Nesprávné použití této flexibility může negativně ovlivnit výkonnost formuláře. Pro maximalizaci výkonu formuláře pomocí implementace přizpůsobení psaných v jazyce JavaScript by vývojáři měli použít následující strategie.

Při žádosti o data používat asynchronní síťové požadavky

Pokud jsou pro přizpůsobení nutná další data, požadujte je asynchronně, nikoli synchronně. U událostí, které podporují čekání na asynchronní kód, jako jsou události OnLoad a OnSave formuláře, by obslužné rutiny událostí měly vrátit Promise, aby platforma počkala do vyřízení Promise. Platforma zobrazí příslušné uživatelské rozhraní, zatímco uživatel čeká na dokončení události.

U událostí, které nepodporují čekání na asynchronní kód, jako je událost OnChange formuláře, můžete použít náhradní řešení k zastavení interakce s formulářem, zatímco kód provádí asynchronní požadavek – pomocí showProgressIndicator. Je to lepší než používání synchronních požadavků, protože uživatelé budou stále moci komunikovat s jinými částmi aplikace v době, kdy se zobrazuje indikátor průběhu.

Zde je příklad použití asynchronního kódu v bodech synchronního rozšíření.

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

Při používání asynchronního kódu v obslužných rutinách událostí, které nepodporují čekání na asynchronní kód, buďte opatrní. To platí zejména pro kód, u kterého je třeba provést akci nebo zpracovat řešení asynchronního kódu. Asynchronní kód může způsobit problémy, pokud obslužná rutina řešení očekává, že kontext aplikace zůstane stejný jako při spuštění asynchronního kódu. Váš kód by měl po každém asynchronním bodu pokračování zkontrolovat, zda je uživatel ve stejném kontextu.

Například v obslužné rutině událostí může být kód pro vytvoření síťového požadavku a změnu ovládacího prvku, který má být zakázán na základě dat odezvy. Než bude odpověď z požadavku přijata, uživatel mohl interagovat s ovládacím prvkem nebo přejít na jinou stránku. Protože je uživatel na jiné stránce, kontext formuláře nemusí být k dispozici, což může vést k chybám, nebo může dojít k jinému nežádoucímu chování.

Asynchronní podpora v událostech OnLoad a OnSave formulářů

Události OnLoad a OnSave formuláře podporují obslužné rutiny, které vracejí Promise. Události počkají na vyřešení všech Promise vrácených obslužnou rutinou, a to až do časového limitu. Tuto podporu lze aktivovat prostřednictvím nastavení aplikace.

Další informace:

Omezte množství dat požadovaných během načítání formuláře

Vyžadujte pouze minimální množství dat, které je nutné k provedení obchodní logiky ve formuláři. Ukládejte data, která jsou požadována, co nejvíce do mezipaměti, zejména data, která se často nemění nebo nemusí být čerstvá. Představte si například, že existuje formulář, který požaduje data z tabulky setting. Na základě údajů v tabulce setting se formulář může rozhodnout skrýt část formuláře. V tomto případě může JavaScript ukládat data do mezipaměti sessionStorage, takže data jsou požadována pouze jednou za relaci (onLoad1). Pokud JavaScript používá data ze sessionStorage při požadavku na data pro další navigaci do formuláře (onLoad2), může být také použita strategie stale-while-revalidate. A konečně je možné použít deduplikační strategii v případě, že je obslužný program volán vícekrát za sebou (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   
    }
}

Místo vytváření požadavků použijte informace dostupné v klientském rozhraní API. Namísto vyžadování rolí zabezpečení uživatele při načítání formulářů můžete například použít getGlobalContext.userSettings.roles.

Načítejte kód pouze v případě potřeby

Pro události v konkrétním formuláři načtěte pouze tolik kódu, kolik je potřeba. Pokud máte kód, který je určen pouze pro formulář A a formulář B, neměl by být součástí knihovny, která je načtena pro formulář C. Měl by to být ve vlastní knihovně.

Vyhněte se načítání knihoven v události OnLoad, pokud jsou použity pouze v událostech OnChange nebo OnSave. Načítejte je v těchto událostech. Platforma tak může odložit jejich načítání až po načtení formuláře. Více informací: Optimalizace výkonu formuláře

Odeberte použití konzolových API v produkčním kódu

Nepoužívejte metody konzolového API jako console.log v produkčním kódu. Protokolování dat do konzoly může výrazně zvýšit nároky na paměť a může zabránit vyčištění dat v paměti. To může vést k tomu, že se aplikace časem zpomalí a nakonec se zhroutí.

Vyhněte se únikům paměti

Úniky paměti ve vašem kódu mohou časem vést ke zpomalení a nakonec způsobit selhání aplikace. K únikům paměti dochází, když se aplikaci nepodaří uvolnit paměť, která již není potřeba. Při všech úpravách a u všech komponent kódu ve formuláři byste měli:

  • Důkladně zvážit a otestovat scénáře pro cokoli zodpovědné za čištění paměti, jako jsou třídy zodpovědné za správu životního cyklu objektů.
  • Vyčistit všechny posluchače událostí a odběry, zejména pokud jsou na objektu window.
  • Vyčistit všechny časovače jako setInterval.
  • Nepoužívat, omezit a vyčistit reference na globální nebo statické objekty.

U vlastních ovládacích komponent lze čištění provést v metodě destroy.

Další informace o opravách problémů s pamětí naleznete v této dokumentaci pro vývojáře Edge.

Nástroje, které můžete použít ke zvýšení výkonu aplikací

Tato část popisuje nástroje, které vám mohou pomoci porozumět problémům s výkonem a nabídnout doporučení pro optimalizaci vašich přizpůsobení v modelem řízených aplikacích.

Přehledy výkonu

Přehledy výkonu jsou samoobslužný nástroj pro tvůrce podnikových aplikací, který analyzuje běhová data telemetrie a poskytuje seznam doporučení podle priorit, který má pomoci zlepšit výkon modelem řízených aplikací. Tato funkce poskytuje denní sadu analytických poznatků souvisejících s výkonem modelem řízené aplikace Power Apps nebo zapojení zákazníků, jako je Dynamics 365 Sales nebo Dynamics 365 Service, s doporučeními a akčními položkami. Tvůrci podnikových aplikací mohou zobrazit podrobné statistiky výkonu na úrovni aplikace v Power Apps. Více informací: Co jsou přehledy výkonu? (preview)

Kontrola řešení

Kontrola řešení je výkonný nástroj, který dokáže analyzovat přizpůsobení klientů a serverů z hlediska problémů s výkonem nebo spolehlivostí. Může analyzovat JavaScript na straně klienta, formuláře XML a doplňky .NET na straně serveru a poskytovat cílené informace o tom, co může zpomalit koncové uživatele. Doporučujeme spustit kontrolu řešení pokaždé, když publikujete změny ve vývojovém prostředí, abyste odhalili jakékoli problémy s výkonem předtím, než aplikaci začnou používat koncoví uživatelé. Další informace: Použití kontroly řešení k ověření vašich aplikací řízených podle modelu v Power Apps

Několik příkladů problémů souvisejících s výkonem nalezených pomocí nástroje Kontrola řešení:

  • il-specify-column. Vyvarujte se výběru všech sloupců pomocí rozhraní API dotazu Dataverse.
  • web-use-async. Pracujte s prostředky HTTP a HTTPS asynchronně.
  • web-avoid-ui-refreshribbon. Vyhněte se používání metody refreshRibbon v události OnLoad a metodě EnableRule formuláře.

Kontrola objektů

Kontrola objektů spouští diagnostiku objektů komponent v rámci vašeho řešení v reálném čase. Pokud jsou zjištěny problémy, vrátí se doporučení, které popisuje, jak problém vyřešit. Více informací: Použití kontroly objektů k diagnostice komponenty řešení (preview)

Další kroky

Návrh hlavních produktivních formulářů v modelem řízených aplikacích