Del via


Utforme skjemaer for ytelse i modelldrevne apper

Å bygge opp opplevelser der oppgaver kan utføres raskt og effektivt, er avgjørende for brukertilfredsheten. Modelldrevne apper kan tilpasses for å skape opplevelse som tilfredsstiller brukernes behov, men det er viktig å vite hvordan du koder, bygger og kjører modelldrevne apper raskt når en bruker åpner og navigerer i appen når han/hun arbeider med daglige oppgaver. Ytelse har vist seg å være en nøkkelfaktor for misnøye i en app når den ikke er optimalisert for ytelse.

Intelligente tilpassinger og skjemaer for ytelse er viktige aspekter ved bygging av svært effektive og produktive skjemaer. Det er også viktig å sørge for at du bygger svært produktive skjemaer med de beste fremgangsmåtene i utforming og oppsett av brukergrensesnitt. Hvis du vil ha informasjon om utforming av skjemaer for effektivitet og produktivitet, kan du se Utforme produktive hovedskjemaer i modelldrevne apper.

Det er også viktig å sørge for at brukerne bruker anbefalte og støttede enheter og at de har minimumskrav til spesifikasjoner. Mer informasjon: Støttede nettlesere og mobilenheter

Arbeid med data og faner

Denne delen viser hvordan kontroller som viser data og faner, har innvirkning på skjemaytelsen.

Viktigheten av standardfanen

Standardfanen er den første utvidede fanen i et skjema. Den spiller en spesiell rolle under innlasting av en skjemaside. Kontrollene på standardfanen gjengis alltid når du åpner en oppføring. Logikken for initialisering av kontroller, for eksempel henting av data, startes spesifikt for hver kontroll på fanen.

En sekundær fane utfører derimot ikke denne initialiseringen på kontrollene når skjemaet lastes inn for første gang. Initialiseringen av kontrollen skjer i stedet når den sekundære fanen åpnes, enten via brukersamhandling eller setFocus-klient-API-metoden. Dette gir en mulighet til å skjerme den første skjemainnlastningen fra overdreven kontrollbehandling ved å plassere bestemte kontroller på sekundære faner i stedet for på standardfanen. Strategien for kontrollplassering kan derfor ha en betydelig innvirkning på responsen til den første skjemainnlastningen. En mer responsiv standardfane gir en bedre generell opplevelse ved endring av viktige felter, samhandling med kommandolinjen og utforsking av andre faner og deler.

Plasser alltid kontroller som brukes mest, øverst på standardfanen. Oppsett og informasjonsarkitektur er ikke bare viktig for ytelse, men også for å forbedre produktiviteten når brukere samhandler med data i skjemaet. Mer informasjon: Utforme produktive hovedskjemaer i modelldrevne apper

Datadrevne kontroller

Kontroller som krever ekstra data utover hovedoppføringen, gir mest belastning på respons og innlastingshastighet for skjemaet. Disse kontrollene henter data over nettverket og involverer ofte en venteperiode (sett på som fremdriftsindikatorer) fordi det kan ta tid å overføre dataene.

Noen av de datadrevne kontrollene omfatter følgende:

Behold bare de mest brukte kontrollene i standardkategorien. De resterende datadrevne kontrollene bør distribueres til sekundære kategorier slik at standardkategorien lastes inn raskt. I tillegg reduserer denne oppsettstrategien sjansen for å hente data som ender opp med å bli ubrukt.

Det finnes andre kontroller som er mindre virkningsfulle enn de datadrevne kontrollene, men som likevel kan delta i strategien for oppsett ovenfor for å oppnå best mulig ytelse. Disse kontrollene omfatter følgende:

Webleser

Denne delen dekker gode fremgangsmåter for bruk i nettlesere.

Ikke åpne nye vinduer

openForm-klient-API-metoden tillater et parameteralternativ for å vise et skjema i et nytt vindu. Ikke bruk denne parameteren, eller sett den til usann. Hvis du setter den til usann, utfører openForm-metoden standardfunksjonaliteten for visning av skjemaet ved hjelp av det eksisterende vinduet. Det er også mulig å kalle JavaScript-funksjonen window.open direkte fra et egendefinert skript eller et annet program. Dette bør imidlertid også unngås. Åpning av et nytt vindu betyr at alle sideressursene må hentes og lastes inn fra bunnen av, fordi siden ikke kan bruke bufringsfunksjonene for data i minnet mellom et tidligere innlastet skjema og skjemaet i et nytt vindu. Som et alternativ til å åpne nye vinduer kan du vurdere å bruke flerøktsopplevelsen som gjør det mulig å åpne oppføringer i flere kategorier, samtidig som du maksimerer ytelsesfordelene ved klientbufring.

Bruk moderne nettlesere

Det er viktig å bruke den mest oppdaterte nettleseren for å sikre at den modelldrevne appen kjører så fort som mulig. Årsaken til dette er at mange av ytelsesforbedringene bare kan brukes i nyere moderne nettlesere.

Hvis organisasjonen for eksempel har eldre versjoner av Firefox, ikke-Chromium-baserte nettlesere og så videre, vil mange av ytelsesgevinstene som er innebygd i en modelldrevet app, ikke være tilgjengelig i eldre nettleserversjoner fordi de ikke støtter funksjoner som appen er avhengig av for å kjøre raskt og problemfritt.

I de fleste tilfeller kan du forvente å se forbedringer av sidebelastningen ved bare å bytte til Microsoft Edge, oppdatere til den nyeste gjeldende nettleserversjonen fra en eldre versjon eller flytte til en moderne Chromium-basert nettleser.

JavaScript-tilpassing

Denne delen viser hvordan du kan utføre intelligente tilpassinger når du bruker JavaScript., som hjelper deg med å bygge effektive skjemaer og sider i en modelldrevet app.

Bruk av JavaScript med skjemaer

Muligheten for å tilpasse skjemaer via JavaScript gir profesjonelle utviklere stor fleksibilitet i forhold til hvordan et skjema ser ut og fungerer. Feilaktiv bruk av denne fleksibiliteten kan ha negativ innvirkning på skjemaytelsen. Utviklere bør bruke følgende strategier for å maksimere skjemaytelsen ved implementering av JavaScript-tilpassinger.

Bruk asynkrone nettverksforespørsler når du ber om data

Be om data asynkront i stedet for synkront når ekstra data er nødvendig for tilpassinger. For hendelser som støtter venting på asynkron kode, for eksempel hendelser i skjemaet OnLoad og skjemaet OnSave, bør hendelsesbehandlinger returnere en Promise, slik at plattformen venter til Promise er oppgjort. Plattformen viser et aktuelt brukergrensesnitt mens brukeren venter på at hendelsen skal fullføres.

For hendelser som ikke støtter venting på asynkron kode, for eksempel skjemahendelsen OnChange, kan du bruke en løsning for å stoppe samhandlingen med et skjema når koden gjør en asynkron forespørsel ved hjelp av showProgressIndicator. Dette er bedre enn å bruke synkrone forespørsler fordi brukerne fremdeles vil kunne samhandle med andre deler av programmet når en fremdriftsindikator vises.

Her er et eksempel på bruk av asynkron kode i synkrone utvidelsespunkter.

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

Du bør være forsiktig når du bruker asynkron kode i en hendelsesbehandling som ikke støtter venting på asynkron kode. Dette gjelder spesielt for kode som krever at en handling utføres eller håndteres på løsningen til den asynkrone koden. Asynkron kode kan føre til problemer hvis løsningsbehandleren forventer at programkonteksten forblir den samme som den var da den asynkrone koden ble startet. Koden må kontrollere at brukeren er i samme kontekst etter hvert asynkrone fortsettelsespunkt.

Det kan for eksempel være kode i en hendelsesbehandling for å opprette en nettverksforespørsel og endre en kontroll for å bli deaktivert basert på svardataene. Før svaret fra forespørselen mottas, kan brukeren ha samhandlet med kontrollen eller navigert til en annen side. Siden brukeren er på en annen side, kan det hende at skjemakonteksten ikke er tilgjengelig, noe som kan føre til feil, eller at det kan oppstå annen uønsket virkemåte.

Asynkron støtte i skjemahendelsene OnLoad og OnSave

Skjemahendelsene OnLoad og OnSave støtter behandlinger som returnerer løfter. Hendelsene venter på at eventuelle løfter som er returnert av en behandling, skal løses, frem til en tidsavbruddsperiode. Denne støtten kan aktiveres via appinnstillinger.

Mer informasjon:

Begrens datamengden som blir forespurt under skjemainnlasting

Be bare om minimumsmengden av data som er nødvendig for å utføre forretningslogikk i et skjema. Hurtigbufre dataene som blir forespurt så mye som mulig, spesielt for data som ikke endres ofte eller ikke trenger å være oppdatert. Tenk deg for eksempel at det finnes et skjema som ber om data fra en innstillingstabell. Skjemaet kan velge å skjule en del av skjemaet basert på data i innstillingstabellen. I dette tilfellet kan JavaScript hurtigbufre data i sessionStorage, slik at data bare bes om én gang per økt (onLoad1). En strategi for venting under revalidering kan også brukes der JavaScript bruker dataene fra sessionStorage når du ber om data for neste navigasjon til skjemaet (onLoad2). Til slutt kan en dedupliseringsstrategi brukes i tilfelle en behandler kalles flere ganger i en rad (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   
    }
}

Bruk informasjon som er tilgjengelig i klient-API-en, i stedet for å utføre forespørsler. I stedet for å be om en brukers sikkerhetsroller ved skjemainnlasting, kan du for eksempel bruke getTexttext.userSettings.roles.

Bare last inn kode når det er nødvendig

Last inn så mye kode du trenger for hendelser for et bestemt skjema. Hvis du har kode som bare gjelder for skjema A og skjema B, bør ikke den inkluderes i et bibliotek som lastes inn for skjema C. Den bær være i sitt eget bibliotek.

Unngå lasting av biblioteker i OnLoad-hendelsen hvis de bare brukes for hendelsene OnChange eller OnSave. Last dem i stedet inn i disse hendelsene. På denne måten kan plattformen utsette lasting av dem til skjemaet er lastet inn. Mer informasjon: Optimalisere skjemaytelsen

Fjerne bruk av API-er for konsoll i produksjonskode

Ikke bruk API-metodene for konsoll, for eksempel console.log i produksjonskode. Logging av data til konsollen kan øke minnebehovet betydelig, og det kan føre til at data ikke ryddes i minnet. Dette kan føre til at appen blir tregere over tid og til slutt krasjer.

Unngå minnelekkasjer

Minnelekkasjer i koden kan føre til lavere ytelse over tid og til at appen krasjer. Minnelekkasjer oppstår når programmet ikke frigir minne som ikke lenger trengs. Gjør følgende med alle tilpassinger og kodekomponenter for skjemaet:

  • Foreta grundig vurdering og testing av scenarioer i forbindelse med alt som er ansvarlig for å rydde opp i minnet, for eksempel klasser med ansvar for å håndtere livssyklusen til objekter.
  • Rydd opp i alle hendelseslyttere og -abonnementer, særlig hvis de er på window-objektet.
  • Rydd opp i alle tidtakere som setInterval.
  • Unngå, begrens og rydd opp i referanser til globale eller statiske objekter.

Når det gjelder egendefinerte kontrollkomponenter, kan oppryddingen gjøres i destroy-metoden.

Hvis du vil ha mer informasjon om hvordan du løser minneproblemer, kan du gå til denne dokumentasjonen for Edge-utviklere.

Verktøy du kan bruke for å gjøre apper effektive

Denne delen beskriver verktøyene som kan hjelpe deg med å forstå ytelsesproblemer og gi anbefalinger om hvordan du optimaliserer tilpassingene i modelldrevne apper.

Ytelsesinnsikt

Ytelsesinnsikt er et selvbetjent verktøy for utviklere av virksomhetsapper som analyserer telemetridata ved kjøretid og gir en prioritert liste over anbefalinger som bidrar til å forbedre ytelsen til modelldrevne apper. Denne funksjonen inneholder et daglig sett med analytisk innsikt relatert til ytelsen til en modelldrevet Power Apps-app eller kundeengasjementsapp, for eksempel Dynamics 365 Sales eller Dynamics 365 Service, med anbefalinger og handlingsbare elementer. Utviklere av bedriftsapper kan vise detaljert ytelsesinnsikt på appnivå i Power Apps. Mer informasjon: Hva er ytelsesinnsikt? (forhåndsversjon)

Løsningskontroll

Løsningskontroll er et kraftig verktøy som kan analysere klient- og servertilpassinger for ytelses- eller pålitelighetsproblemer. Det kan analysere JavaScript, skjema-XML og .NET-plugin-moduler på serversiden og gi målrettet innsikt i hva som kan gjøre opplevelsen tregere for sluttbrukere. Vi anbefaler at du kjører løsningskontroll hver gang du publiserer endringer i et utviklingsmiljø, slik at eventuelle ytelsesproblemer vises før de når sluttbrukerne. Mer informasjon: Bruke løsningskontroll til å validere de modelldrevne appene i Power Apps

Her er noen eksempler på ytelsesrelaterte problemer som finnes i løsningskontrollen:

Objektkontroll

Objektkontroll kjører diagnose i sanntid på komponentobjekter i løsningen. Hvis det oppdages problemer, returneres en anbefaling som beskriver hvordan problemet kan løses. Mer informasjon: Bruk objektkontroll til å diagnostisere en løsningskomponent (forhåndsversjon)

Neste trinn

Utforme produktive hovedskjemaer i modelldrevne apper