Har du noen gang trengte å gå gjennom en liste, men operasjonen tok lang tid å fullføre? Har du noen gang hatt et programkrasj fordi en operasjon brukte for mye minne? Dette skjedde med meg da jeg prøvde å implementere en funksjon som genererer primtal.
Å generere primtal til opptil en million tok langt mer tid enn jeg ville ha likt. Men det var umulig å generere tall på opptil 10 millioner. Mitt program ville krasje eller bare henge. Jeg brukte allerede sikten til Eratosthenes, som skal være mer effektiv til å generere primater enn brute force approach.
Hvis du befinner deg i en lignende situasjon, kan du prøve å bruke en annen algoritme. Det er søk og sorteringsalgoritmer som fungerer bedre på større innganger. Ulempen er at algoritmer kan være vanskeligere å forstå med en gang. Et annet alternativ er å bruke et annet programmeringsspråk.
Et kompilert språk kan være i stand til å behandle koden betydelig raskere. Men å bruke et annet språk kan ikke være praktisk. Du kan også prøve å bruke flere tråder. Igjen kan det ikke være praktisk fordi programmeringsspråket ditt måtte støtte dette.
Heldigvis, med JavaScript, er det et annet alternativ. Hvis du har en beregningsintensiv oppgave, kan du bruke iteratorer og generatorer til å få litt effektivitet. Iteratorer er en egenskap for visse JavaScript-samlinger.
Iteratorer forbedrer effektiviteten ved å la deg konsumere elementene i en liste en om gangen som om de var en strøm. Generatorer er en spesiell type funksjon som kan stoppe kjøringen. Ved å invitere en generator kan du produsere data en bit om gangen uten å måtte lagre den i en liste først.
Først, la oss se på de forskjellige måtene du kan løse gjennom samlinger i JavaScript. En sløyfe av skjemaet for (initial; betingelse; trinn) ...
vil utføre kommandoene i kroppen et bestemt antall ganger. På samme måte vil en stundsløyfe utføre kommandoene i sin kropp så lenge tilstanden er sant.
Du kan bruke disse løkkene til å krysse en liste ved å øke en indeksvariabel ved hver iterasjon. En iterasjon er en utførelse av kroppens sløyfe. Disse løkkene vet ikke om strukturen på listen din. De fungerer som tellere.
EN for i
loop og a for / av
loop er designet for å iterere over bestemte datastrukturer. Iterering over en datastruktur betyr at du går gjennom hver av elementene. EN for i
loop iterates over tastene i et vanlig JavaScript-objekt. EN for / av
loop iterates over verdiene av en iterable. Hva er en iterbar? Enkelt sagt, en iterbar er et objekt som har en iterator. Eksempler på iterables er arrays og sett. Iteratoren er en egenskap av objektet som gir en mekanisme for å krysse objektet.
Hva gjør en iterator spesiell er hvordan det krysser en samling. Andre sløyfer må laste hele samlingen opp foran for å iterere over den, mens en iterator bare trenger å kjenne gjeldende posisjon i samlingen.
Du får tilgang til det nåværende elementet ved å ringe iteratorens neste metode. Den neste metoden vil returnere verdien til gjeldende element og en boolsk for å indikere når du har nådd slutten av samlingen. Følgende er et eksempel på å lage en iterator fra en matrise.
const alpha = ['a', 'b', 'c']; const it = alpha [symbol.iterator] (); it.next (); // verdi: 'a', ferdig: false it.next (); // verdi: 'b', ferdig: false it.next (); // verdi: 'c', ferdig: false it.next (); // verdi: undefined, ferdig: true
Du kan også iterere over verdiene til iteratoren ved hjelp av a for / av
sløyfe. Bruk denne metoden når du vet at du vil få tilgang til alle elementene i objektet. Slik bruker du en løkke for å iterere gjennom den forrige listen:
for (const elem av det) console.log (elem);
Hvorfor vil du bruke en iterator? Å bruke en iterator er gunstig når beregningsprisen for å behandle en liste er høy. Hvis du har en stor datakilde, kan det føre til problemer i programmet hvis du prøver å iterere over det fordi hele samlingen må lastes inn.
Med en iterator kan du laste dataene i biter. Dette er mer effektivt fordi du bare manipulerer den delen av listen du trenger, uten å pådra seg ekstrakostnaden for å behandle hele listen.
Et eksempel kan være at du har lastet data fra en fil eller database, og du vil gradvis vise informasjonen på skjermen. Du kan lage en iterator fra dataene og sette opp en hendelseshåndterer for å hente noen få ting hver gang hendelsen oppstår. Dette er et eksempel på hvordan en slik implementering kan se ut:
la innlegg = last (url); la det = innlegg [Symbol.iterator] (); funksjonlastPoster (iterable, count) for (la i = 0; i < count; i++) display(iterable.next().value); document.getElementById('btnNext').onclick = loadPosts(it, 5);
Hvis du vil bygge en samling, kan du gjøre det med en generator. En generatorfunksjon kan returnere verdier en om gangen ved å stoppe kjøringen ved hver iterasjon. Når du lager en forekomst av en generator, kan disse elementene nås med en iterator. Dette er det generelle syntaksen for å skape en generatorfunksjon:
funksjon * genFunc () ... yield value;
De *
betyr at dette er en generatorfunksjon. De utbytte
Søkeordet pauser vår funksjon og leverer tilstanden til generatoren på det aktuelle tidspunktet. Hvorfor skulle du bruke en generator? Du vil bruke en generator når du algoritmisk skal produsere en verdi i en samling. Det er spesielt nyttig hvis du har en veldig stor eller uendelig samling. La oss se på et eksempel for å forstå hvordan dette hjelper oss.
Anta at du har et online bassengspill du har bygget, og du vil matche spillere til spillrom. Målet ditt er å generere alle måtene du kan velge to forskjellige spillere fra listen over 2000 spillere. De to-spiller kombinasjonene generert fra listen ['a', 'b', 'c', 'd']
ville vært ab, ac, ad, bc, bd, cd
. Dette er en løsning ved hjelp av nestede løkker:
funksjonskombinasjoner (liste) const n = list.length; la resultatet = []; for (la jeg = 0; jeg < n - 1; i++) for (let j = i + 1; j < n; j++) result.push([list[i], list[j]]); return result; console.log(combos(['a', 'b', 'c', 'd']));
Prøv nå å utføre funksjonen med en liste med 2000 elementer. (Du kan initialisere listen med en for-løkke som legger tallene 1 til 2000 til en matrise). Hva skjer nå når du kjører koden din?
Når jeg kjører koden i en online-editor, krasjer websiden. Når jeg prøver det ut i konsollen i Chrome, kan jeg se utskriften sakte utskrift. Men min datamaskin CPU begynner å gå inn i overdrive, og jeg må tvinge avslutte Chrome. Dette er den reviderte koden ved hjelp av en generatorfunksjon:
funksjon * kombinasjoner (liste) const n = list.length; for (la jeg = 0; jeg < n - 1; i++) for (let j = i + 1; j < n; j++) yield [list[i], list[j]]; let it = combos(['a', 'b', 'c', 'd']); it.next();
Et annet eksempel er om vi ønsket å generere tallene i Fibonacci-sekvensen til uendelig. Her er en implementering:
funksjon * fibGen () la nåværende = 0; la neste = 1; mens (sann) gi strøm; la nextNum = nåværende + neste; nåværende = neste; neste = nextNum; la det = fibGen (); . It.next () verdi; // 0 det.neste (). Verdi; // 1 det.neste (). Verdi; // 1 det.neste (). Verdi; // 2
Normalt vil en uendelig sløyfe krasje programmet ditt. De fibGen
funksjonen er i stand til å løpe for alltid fordi det ikke er noen stopptilstand. Men siden det er en generator, kontrollerer du når hvert trinn utføres.
Iteratorer og generatorer kommer til nytte når du ønsker å behandle en samling trinnvis. Du får effektivitet ved å holde oversikt over samlingenes tilstand i stedet for alle elementene i samlingen. Elementer i samlingen evalueres en om gangen, og evalueringen av resten av samlingen blir forsinket til senere.
Iteratorer gir en effektiv måte å krysse og manipulere store lister på. Generatorer gir en effektiv måte å bygge lister på. Du bør prøve ut disse teknikkene når du ellers ville bruke en kompleks algoritme eller implementere parallell programmering for å optimalisere koden din.
Hvis du leter etter flere ressurser for å studere eller bruke i arbeidet ditt, sjekk ut hva vi har tilgjengelig på Envato Market.
Vi har bygget en komplett guide for å hjelpe deg med å lære JavaScript, enten du er bare i gang som webutvikler eller du vil utforske mer avanserte emner.