Tilbake
5.5
Asynkron programmering og API-er

5.5 Asynkron programmering og API-er

Forstå asynkron programmering med Promises og async/await, og hent data med fetch().

70 min
8 oppgaver
Asynkron programmeringAPIfetch()Promise
Du leser den tradisjonelle versjonen
Din fremgang i kapitlet
0 / 8 oppgaver

Asynkron programmering og API-er

Hittil har JavaScript-koden vår kjørt synkront – instruksjon for instruksjon, fra topp til bunn. Men mange oppgaver i moderne webutvikling tar tid: hente data fra en server, laste bilder, vente på brukerinput. Hvis JavaScript måtte vente på at hver slik operasjon ble ferdig før den fortsatte, ville nettsiden fryse og bli ubrukelig.

Løsningen er asynkron programmering – en modell der tidkrevende operasjoner startes og kjører i bakgrunnen, mens resten av programmet fortsetter. Når operasjonen er ferdig, varsles programmet og kan behandle resultatet.

I dette kapittelet lærer vi om Promises, async/await og den kanskje viktigste praktiske ferdigheten i moderne JavaScript: å hente data fra API-er (Application Programming Interfaces) med fetch().

Asynkron programmering
Asynkron programmering er en programmeringsmodell der operasjoner kan starte og fullføre uavhengig av programflyten, uten å blokkere kjøringen av annen kode. I JavaScript betyr dette at tidkrevende operasjoner som nettverksforespørsler, fillesing og timere starter i bakgrunnen, mens programmet fortsetter å kjøre. Når den asynkrone operasjonen er ferdig, varsles programmet gjennom en callback-funksjon, et Promise eller async/await.

La oss se forskjellen mellom synkron og asynkron kode:

Synkron kode (blokkerende)

console.log("Steg 1");
console.log("Steg 2");  // Venter til steg 1 er ferdig
console.log("Steg 3");  // Venter til steg 2 er ferdig
// Utskrift: Steg 1, Steg 2, Steg 3 (i rekkefølge)

Asynkron kode (ikke-blokkerende)

console.log("Steg 1");

setTimeout(() => {
  console.log("Steg 2 (etter 2 sekunder)");
}, 2000);

console.log("Steg 3");
// Utskrift: Steg 1, Steg 3, Steg 2 (etter 2 sek)

I det asynkrone eksemplet kjøres «Steg 3» før «Steg 2» fordi setTimeout er asynkron – den starter en timer i bakgrunnen og lar resten av koden kjøre videre. Når timeren utløper etter 2 sekunder, kjøres callback-funksjonen.

setTimeout er det enkleste eksemplet på asynkron kode, men i praksis er det nettverksforespørsler (henting av data fra API-er) som er den viktigste bruken av asynkron programmering.

API (Application Programming Interface)

Et API er et grensesnitt som lar programmer kommunisere med hverandre etter bestemte regler. Web-API-er er tjenester som leverer data over internett via HTTP-forespørsler. Når JavaScript henter værdata, kartinformasjon eller nyheter fra en ekstern tjeneste, kommuniserer det med et API. API-er mottar forespørsler og returnerer data, vanligvis i JSON-format. De fleste moderne nettsider og apper bruker API-er for å hente og sende data.

fetch() er den innebygde JavaScript-funksjonen for å sende HTTP-forespørsler. Den er asynkron og returnerer et Promise:

fetch("https://api.eksempel.no/data")
  .then(response => response.json())
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    console.error("Feil:", error);
  });

La oss bryte ned hva som skjer:

1. fetch(url) sender en HTTP GET-forespørsel til URL-en
2. .then(response => response.json()) tar svaret fra serveren og konverterer det fra JSON-tekst til et JavaScript-objekt
3. .then(data => { ... }) lar deg bruke de konverterte dataene
4. .catch(error => { ... }) fanger opp feil (f.eks. nettverksproblemer)

Praktisk eksempel med et ekte API

// Hent et tilfeldig vitseriat fra et åpent API
fetch("https://official-joke-api.appspot.com/random_joke")
  .then(response => response.json())
  .then(joke => {
    console.log(joke.setup);
    console.log(joke.punchline);
  })
  .catch(error => {
    console.error("Kunne ikke hente vits:", error);
  });

Denne koden sender en forespørsel til et API som returnerer tilfeldige vitser i JSON-format, konverterer svaret til et JavaScript-objekt, og skriver ut oppsett og poeng.

Promise

Et Promise er et JavaScript-objekt som representerer det fremtidige resultatet av en asynkron operasjon. Navnet «promise» (løfte) kommer av at objektet gir et løfte om at det vil levere et resultat senere. Et Promise kan ha tre tilstander: pending (operasjonen er i gang), fulfilled (operasjonen lyktes og har et resultat) eller rejected (operasjonen feilet). Du håndterer utfallet med .then() for suksess og .catch() for feil.

Promise-kjeder med .then() kan bli vanskelige å lese. Moderne JavaScript tilbyr async/await som gjør asynkron kode mye enklere:

async function hentData() {
  try {
    const response = await fetch("https://api.eksempel.no/data");
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error("Feil:", error);
  }
}

hentData();

Nøkkelord:
- async foran funksjonen markerer den som asynkron
- await pauser funksjonen til Promiset er fullført (kan bare brukes inne i async-funksjoner)
- try/catch håndterer feil på en oversiktlig måte

Sammenligning: .then() vs. async/await

// Med .then() (eldre stil)
fetch("https://api.eksempel.no/brukere")
  .then(response => response.json())
  .then(brukere => {
    console.log(brukere);
  })
  .catch(error => {
    console.error(error);
  });

// Med async/await (moderne, anbefalt)
async function hentBrukere() {
  try {
    const response = await fetch("https://api.eksempel.no/brukere");
    const brukere = await response.json();
    console.log(brukere);
  } catch (error) {
    console.error(error);
  }
}

Begge gjør nøyaktig det samme, men async/await-versjonen er lettere å lese fordi den ser ut som vanlig synkron kode.

Nettverksforespørsler kan feile av mange grunner: ingen internettforbindelse, serveren er nede, feil URL, API-nøkkel er ugyldig, osv. God feilhåndtering er derfor avgjørende.

Sjekke HTTP-statuskoden

fetch() kaster bare en feil ved nettverksproblemer – den anser HTTP-feil som 404 og 500 som vellykkede forespørsler. Du må sjekke statuskoden selv:

async function hentData(url) {
  try {
    const response = await fetch(url);

    if (!response.ok) {
      throw new Error("HTTP-feil: " + response.status);
    }

    const data = await response.json();
    return data;

  } catch (error) {
    console.error("Noe gikk galt:", error.message);
    return null;
  }
}

response.ok er true for statuskoder 200-299 og false for andre. Ved å kaste en feil med throw new Error() sikrer vi at feil fanges av catch-blokken.

Vise feilmeldinger til brukeren

async function lastInnVarsel() {
  const statusDiv = document.querySelector("#status");
  statusDiv.textContent = "Laster data...";

  try {
    const response = await fetch("https://api.met.no/weatherapi");

    if (!response.ok) {
      throw new Error("Kunne ikke hente værdata.");
    }

    const data = await response.json();
    statusDiv.textContent = "";
    visVardata(data);

  } catch (error) {
    statusDiv.textContent = "Feil: " + error.message;
    statusDiv.style.color = "red";
  }
}

Hittil har vi bare hentet data (GET). For å sende data til en server bruker vi POST-forespørsler:

async function sendKommentar(tekst) {
  try {
    const response = await fetch("https://api.eksempel.no/kommentarer", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        innhold: tekst,
        tidspunkt: new Date().toISOString(),
      }),
    });

    if (!response.ok) {
      throw new Error("Kunne ikke sende kommentar.");
    }

    const resultat = await response.json();
    console.log("Kommentar lagret:", resultat);

  } catch (error) {
    console.error("Feil:", error.message);
  }
}

fetch() tar et valgfritt options-objekt som andre argument:
- method: HTTP-metoden (POST, PUT, DELETE osv.)
- headers: Metainformasjon, her spesifiserer vi at vi sender JSON
- body: Selve dataene, konvertert til JSON-streng med JSON.stringify()

✏️Komplett eksempel: Vise data fra et API i DOM-en

Her er et komplett eksempel som henter brukerdata fra et åpent API og viser det på nettsiden:

HTML:

<h2>Brukeroversikt</h2>
<button id="lastInn">Last inn brukere</button>
<div id="status"></div>
<div id="brukerliste"></div>

JavaScript:

const knapp = document.querySelector("#lastInn");
const statusDiv = document.querySelector("#status");
const listeDiv = document.querySelector("#brukerliste");

knapp.addEventListener("click", async function () {
  statusDiv.textContent = "Laster...";
  listeDiv.innerHTML = "";

  try {
    const response = await fetch("https://jsonplaceholder.typicode.com/users");

    if (!response.ok) {
      throw new Error("Serverfeil: " + response.status);
    }

    const brukere = await response.json();
    statusDiv.textContent = brukere.length + " brukere funnet:";

    brukere.forEach(bruker => {
      const kort = document.createElement("div");
      kort.classList.add("bruker-kort");
      kort.innerHTML = `
        <h3>${bruker.name}</h3>
        <p>E-post: ${bruker.email}</p>
        <p>By: ${bruker.address.city}</p>
      `;
      listeDiv.appendChild(kort);
    });

  } catch (error) {
    statusDiv.textContent = "Feil: " + error.message;
    statusDiv.style.color = "red";
  }
});

Dette eksempelet kombinerer alt vi har lært: hendelseshåndtering (klikk-lytter), asynkron programmering (async/await med fetch), feilhåndtering (try/catch), JSON-parsing og DOM-manipulering (createElement, innerHTML, appendChild).

📝Oppgave 5.5.1

Hva betyr det at JavaScript er asynkront?

📝Oppgave 5.5.2

Hva er et API i websammenheng?

📝Oppgave 5.5.3

Hva skrives ut av denne koden?

console.log("A");
setTimeout(() => console.log("B"), 0);
console.log("C");

📝Oppgave 5.5.4

Hva gjør response.json() i en fetch()-forespørsel?

📝Oppgave 5.5.5

Skriv en asynkron funksjon hentLand(navn) som bruker fetch() og async/await til å hente informasjon om et land fra API-et https://restcountries.com/v3.1/name/{navn}. Funksjonen skal skrive ut landets offisielle navn og befolkningstall til konsollen. Inkluder feilhåndtering med try/catch.

📝Oppgave 5.5.6

Lag en komplett nettside-funksjon som henter en liste med brukere fra https://jsonplaceholder.typicode.com/users og viser dem som kort i en <div id="brukere">. Hvert kort skal vise brukerens navn, e-post og firma. Vis en "Laster..."-melding mens data hentes, og en feilmelding hvis noe går galt. Bruk async/await, DOM-manipulering og feilhåndtering.

📝Oppgave 5.5.7

Hvorfor kaster ikke fetch() en feil for HTTP-statuskode 404 (Ikke funnet)?

📝Oppgave 5.5.8

Skriv en async funksjon sendTilbakemelding(navn, melding) som sender en POST-forespørsel med JSON-data til https://jsonplaceholder.typicode.com/posts. Dataene skal inneholde title (navnet), body (meldingen) og userId satt til 1. Funksjonen skal returnere det opprettede objektet fra serveren, eller null ved feil. Inkluder korrekte headers og feilhåndtering.

Oppsummering

I dette kapittelet har du lært:

- Asynkron programmering: operasjoner uten å blokkere koden.
- API: grensesnitt som lar programmer kommunisere.
- fetch(): henter data fra eksterne API-er.
- Promise: representerer et fremtidig resultat.
- async/await: moderne, lesbar syntaks for asynkron kode.

Noekkelbegreper


BegrepForklaring
Asynkron programmeringOperasjoner som ikke blokkerer koden
APIGrensesnitt for kommunikasjon mellom programmer
PromiseObjekt for fremtidig resultat av asynkron operasjon

Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.