19 KiB
Browserudvidelsesprojekt del 2: Kald en API, brug lokal lagring
Quiz før forelæsning
Introduktion
Kan du huske den browserudvidelse, du begyndte at bygge? Lige nu har du en flot formular, men den er i bund og grund statisk. I dag vil vi give den liv ved at forbinde den til rigtige data og give den hukommelse.
Tænk på Apollo-missionens kontrolcomputere - de viste ikke bare fast information. De kommunikerede konstant med rumfartøjet, opdaterede med telemetridata og huskede kritiske missionparametre. Det er den slags dynamisk adfærd, vi bygger i dag. Din udvidelse vil hente data fra internettet, indsamle reelle miljødata og huske dine indstillinger til næste gang.
API-integration kan lyde komplekst, men det handler i bund og grund om at lære din kode at kommunikere med andre tjenester. Uanset om du henter vejroplysninger, sociale mediefeeds eller information om CO2-aftryk, som vi vil gøre i dag, handler det om at etablere disse digitale forbindelser. Vi vil også udforske, hvordan browsere kan gemme information - ligesom biblioteker har brugt kortkataloger til at huske, hvor bøger hører hjemme.
Ved slutningen af denne lektion vil du have en browserudvidelse, der henter rigtige data, gemmer brugerpræferencer og giver en glidende oplevelse. Lad os komme i gang!
✅ Følg de nummererede segmenter i de relevante filer for at vide, hvor du skal placere din kode.
Opsæt elementerne til manipulation i udvidelsen
Før din JavaScript kan manipulere grænsefladen, skal den have referencer til specifikke HTML-elementer. Tænk på det som et teleskop, der skal pege på bestemte stjerner - før Galileo kunne studere Jupiters måner, måtte han finde og fokusere på Jupiter selv.
I din index.js-fil opretter vi const-variabler, der fanger referencer til hvert vigtigt form-element. Dette er ligesom hvordan videnskabsfolk mærker deres udstyr - i stedet for at søge gennem hele laboratoriet hver gang, kan de direkte få adgang til det, de har brug for.
// form fields
const form = document.querySelector('.form-data');
const region = document.querySelector('.region-name');
const apiKey = document.querySelector('.api-key');
// results
const errors = document.querySelector('.errors');
const loading = document.querySelector('.loading');
const results = document.querySelector('.result-container');
const usage = document.querySelector('.carbon-usage');
const fossilfuel = document.querySelector('.fossil-fuel');
const myregion = document.querySelector('.my-region');
const clearBtn = document.querySelector('.clear-btn');
Hvad denne kode gør:
- Fanger form-elementer ved hjælp af
document.querySelector()med CSS-klassevælgere - Opretter referencer til inputfelter for regionnavn og API-nøgle
- Etablerer forbindelser til resultatvisningselementer for data om CO2-forbrug
- Opsætter adgang til UI-elementer som indlæsningsindikatorer og fejlmeddelelser
- Gemmer hver elementreference i en
const-variabel for nem genbrug i din kode
Tilføj event listeners
Nu får vi din udvidelse til at reagere på brugerhandlinger. Event listeners er din kodes måde at overvåge brugerinteraktioner på. Tænk på dem som operatører i de tidlige telefoncentraler - de lyttede efter indgående opkald og forbandt de rigtige kredsløb, når nogen ville ringe.
form.addEventListener('submit', (e) => handleSubmit(e));
clearBtn.addEventListener('click', (e) => reset(e));
init();
Forståelse af disse begreber:
- Tilføjer en submit listener til formularen, der aktiveres, når brugere trykker på Enter eller klikker på send
- Forbinder en kliklistener til nulstillingsknappen for at nulstille formularen
- Sender hændelsesobjektet
(e)til håndteringsfunktioner for yderligere kontrol - Kalder
init()-funktionen med det samme for at opsætte udvidelsens starttilstand
✅ Bemærk den korte pilfunktion-syntaks, der bruges her. Denne moderne JavaScript-tilgang er mere elegant end traditionelle funktionsudtryk, men begge fungerer lige godt!
Byg initialiserings- og nulstillingsfunktionerne
Lad os oprette initialiseringslogikken for din udvidelse. init()-funktionen er som et skibs navigationssystem, der kontrollerer sine instrumenter - den bestemmer den aktuelle tilstand og justerer grænsefladen derefter. Den kontrollerer, om nogen har brugt din udvidelse før og indlæser deres tidligere indstillinger.
reset()-funktionen giver brugerne en frisk start - ligesom hvordan videnskabsfolk nulstiller deres instrumenter mellem eksperimenter for at sikre rene data.
function init() {
// Check if user has previously saved API credentials
const storedApiKey = localStorage.getItem('apiKey');
const storedRegion = localStorage.getItem('regionName');
// Set extension icon to generic green (placeholder for future lesson)
// TODO: Implement icon update in next lesson
if (storedApiKey === null || storedRegion === null) {
// First-time user: show the setup form
form.style.display = 'block';
results.style.display = 'none';
loading.style.display = 'none';
clearBtn.style.display = 'none';
errors.textContent = '';
} else {
// Returning user: load their saved data automatically
displayCarbonUsage(storedApiKey, storedRegion);
results.style.display = 'none';
form.style.display = 'none';
clearBtn.style.display = 'block';
}
}
function reset(e) {
e.preventDefault();
// Clear stored region to allow user to choose a new location
localStorage.removeItem('regionName');
// Restart the initialization process
init();
}
Hvad der sker her:
- Henter gemt API-nøgle og region fra browserens lokale lagring
- Kontrollerer, om det er en førstegangsbruger (ingen gemte legitimationsoplysninger) eller en tilbagevendende bruger
- Viser opsætningsformularen for nye brugere og skjuler andre grænsefladeelementer
- Indlæser gemte data automatisk for tilbagevendende brugere og viser nulstillingsmuligheden
- Administrerer brugergrænsefladens tilstand baseret på tilgængelige data
Vigtige begreber om lokal lagring:
- Bevarer data mellem browsersessioner (i modsætning til session storage)
- Gemmer data som nøgle-værdi-par ved hjælp af
getItem()ogsetItem() - Returnerer
null, når der ikke findes data for en given nøgle - Tilbyder en enkel måde at huske brugerpræferencer og indstillinger
💡 Forståelse af browserlagring: LocalStorage er som at give din udvidelse en vedvarende hukommelse. Tænk på, hvordan det gamle bibliotek i Alexandria opbevarede skriftruller - information forblev tilgængelig, selv når forskere forlod og vendte tilbage.
Vigtige egenskaber:
- Bevarer data, selv efter du lukker din browser
- Overlever computer-genstarter og browsernedbrud
- Tilbyder betydelig lagerplads til brugerpræferencer
- Giver øjeblikkelig adgang uden netværksforsinkelser
Vigtig bemærkning: Din browserudvidelse har sin egen isolerede lokale lagring, der er adskilt fra almindelige websider. Dette giver sikkerhed og forhindrer konflikter med andre websites.
Du kan se dine gemte data ved at åbne browserens Developer Tools (F12), navigere til fanen Application og udvide sektionen Local Storage.
⚠️ Sikkerhedsovervejelse: I produktionsapplikationer udgør det sikkerhedsrisici at gemme API-nøgler i LocalStorage, da JavaScript kan få adgang til disse data. Til læringsformål fungerer denne tilgang fint, men rigtige applikationer bør bruge sikker server-side lagring til følsomme legitimationsoplysninger.
Håndter formularindsendelse
Nu vil vi håndtere, hvad der sker, når nogen indsender din formular. Som standard genindlæser browsere siden, når formularer indsendes, men vi vil afbryde denne adfærd for at skabe en mere glidende oplevelse.
Denne tilgang afspejler, hvordan mission control håndterer rumfartøjskommunikation - i stedet for at nulstille hele systemet for hver transmission opretholder de kontinuerlig drift, mens de behandler ny information.
Opret en funktion, der fanger hændelsen med formularindsendelse og udtrækker brugerens input:
function handleSubmit(e) {
e.preventDefault();
setUpUser(apiKey.value, region.value);
}
I ovenstående har vi:
- Forhindret den standardformularindsendelsesadfærd, der ville opdatere siden
- Udtrukket brugerens inputværdier fra API-nøgle- og regionsfelterne
- Sendt formulardataene til
setUpUser()-funktionen til behandling - Opretholdt single-page application-adfærd ved at undgå sideopdateringer
✅ Husk, at dine HTML-formularfelter inkluderer attributten required, så browseren validerer automatisk, at brugerne angiver både API-nøgle og region, før denne funktion kører.
Opsæt brugerpræferencer
setUpUser-funktionen er ansvarlig for at gemme brugerens legitimationsoplysninger og igangsætte det første API-kald. Dette skaber en glidende overgang fra opsætning til visning af resultater.
function setUpUser(apiKey, regionName) {
// Save user credentials for future sessions
localStorage.setItem('apiKey', apiKey);
localStorage.setItem('regionName', regionName);
// Update UI to show loading state
loading.style.display = 'block';
errors.textContent = '';
clearBtn.style.display = 'block';
// Fetch carbon usage data with user's credentials
displayCarbonUsage(apiKey, regionName);
}
Trin for trin, her er hvad der sker:
- Gemmer API-nøgle og regionsnavn i lokal lagring til fremtidig brug
- Viser en indlæsningsindikator for at informere brugerne om, at data hentes
- Fjerner eventuelle tidligere fejlmeddelelser fra visningen
- Viser nulstillingsknappen, så brugerne kan nulstille deres indstillinger senere
- Starter API-kaldet for at hente reelle data om CO2-forbrug
Denne funktion skaber en problemfri brugeroplevelse ved at administrere både databevaring og opdateringer af brugergrænsefladen i én koordineret handling.
Vis data om CO2-forbrug
Nu vil vi forbinde din udvidelse til eksterne datakilder via API'er. Dette forvandler din udvidelse fra et selvstændigt værktøj til noget, der kan få adgang til realtidsinformation fra hele internettet.
Forståelse af API'er
API'er er, hvordan forskellige applikationer kommunikerer med hinanden. Tænk på dem som telegrafsystemet, der forbandt fjerne byer i det 19. århundrede - operatører sendte anmodninger til fjerne stationer og modtog svar med de ønskede oplysninger. Hver gang du tjekker sociale medier, stiller en stemmeassistent et spørgsmål eller bruger en leveringsapp, faciliterer API'er disse dataudvekslinger.
Vigtige begreber om REST API'er:
- REST står for 'Representational State Transfer'
- Bruger standard HTTP-metoder (GET, POST, PUT, DELETE) til at interagere med data
- Returnerer data i forudsigelige formater, typisk JSON
- Tilbyder konsistente, URL-baserede endpoints til forskellige typer anmodninger
✅ CO2 Signal API, som vi vil bruge, giver realtidsdata om kulstofintensitet fra elektriske netværk verden over. Dette hjælper brugere med at forstå miljøpåvirkningen af deres elforbrug!
💡 Forståelse af asynkron JavaScript:
async-nøgleordet gør det muligt for din kode at håndtere flere operationer samtidigt. Når du anmoder om data fra en server, vil du ikke have, at hele din udvidelse fryser - det ville være som om flyveledelsen stoppede alle operationer, mens de ventede på svar fra et fly.Vigtige fordele:
- Opretholder udvidelsens responsivitet, mens data indlæses
- Tillader anden kode at fortsætte med at køre under netværksanmodninger
- Forbedrer kodens læsbarhed sammenlignet med traditionelle callback-mønstre
- Muliggør elegant fejlhåndtering ved netværksproblemer
Her er en hurtig video om async:
🎥 Klik på billedet ovenfor for en video om async/await.
Opret funktionen til at hente og vise data om CO2-forbrug:
// Modern fetch API approach (no external dependencies needed)
async function displayCarbonUsage(apiKey, region) {
try {
// Fetch carbon intensity data from CO2 Signal API
const response = await fetch('https://api.co2signal.com/v1/latest', {
method: 'GET',
headers: {
'auth-token': apiKey,
'Content-Type': 'application/json'
},
// Add query parameters for the specific region
...new URLSearchParams({ countryCode: region }) && {
url: `https://api.co2signal.com/v1/latest?countryCode=${region}`
}
});
// Check if the API request was successful
if (!response.ok) {
throw new Error(`API request failed: ${response.status}`);
}
const data = await response.json();
const carbonData = data.data;
// Calculate rounded carbon intensity value
const carbonIntensity = Math.round(carbonData.carbonIntensity);
// Update the user interface with fetched data
loading.style.display = 'none';
form.style.display = 'none';
myregion.textContent = region.toUpperCase();
usage.textContent = `${carbonIntensity} grams (grams CO₂ emitted per kilowatt hour)`;
fossilfuel.textContent = `${carbonData.fossilFuelPercentage.toFixed(2)}% (percentage of fossil fuels used to generate electricity)`;
results.style.display = 'block';
// TODO: calculateColor(carbonIntensity) - implement in next lesson
} catch (error) {
console.error('Error fetching carbon data:', error);
// Show user-friendly error message
loading.style.display = 'none';
results.style.display = 'none';
errors.textContent = 'Sorry, we couldn\'t fetch data for that region. Please check your API key and region code.';
}
}
Hvad der sker her:
- Bruger den moderne
fetch()-API i stedet for eksterne biblioteker som Axios for renere, afhængighedsfri kode - Implementerer korrekt fejltjek med
response.okfor tidligt at fange API-fejl - Håndterer asynkrone operationer med
async/awaitfor mere læsbar kodeflow - Autentificerer med CO2 Signal API ved hjælp af
auth-token-headeren - Parser JSON-svardata og udtrækker information om kulstofintensitet
- Opdaterer flere UI-elementer med formaterede miljødata
- Tilbyder brugervenlige fejlmeddelelser, når API-kald mislykkes
Vigtige moderne JavaScript-begreber demonstreret:
- Template literals med
${}-syntaks for ren strengformatering - Fejlhåndtering med try/catch-blokke for robuste applikationer
- Async/await-mønster for elegant håndtering af netværksanmodninger
- Objekt-destructuring for at udtrække specifikke data fra API-svar
- Metodekædning til flere DOM-manipulationer
✅ Denne funktion demonstrerer flere vigtige webudviklingskoncepter - kommunikation med eksterne servere, håndtering af autentifikation, databehandling, opdatering af grænseflader og elegant håndtering af fejl. Dette er grundlæggende færdigheder, som professionelle udviklere regelmæssigt bruger.
🎉 Hvad du har opnået: Du har skabt en browserudvidelse, der:
- Forbinder til internettet og henter reelle miljødata
- Bevarer brugerindstillinger mellem sessioner
- Håndterer fejl elegant i stedet for at gå ned
- Tilbyder en glidende, professionel brugeroplevelse
Test dit arbejde ved at køre npm run build og opdatere din udvidelse i browseren. Du har nu en funktionel CO2-aftryk tracker. Den næste lektion vil tilføje dynamisk ikonfunktionalitet for at fuldende udvidelsen.
GitHub Copilot Agent Challenge 🚀
Brug Agent-tilstand til at fuldføre følgende udfordring:
Beskrivelse: Forbedr browserudvidelsen ved at tilføje forbedringer til fejlhåndtering og brugeroplevelsesfunktioner. Denne udfordring vil hjælpe dig med at øve dig i at arbejde med API'er, lokal lagring og DOM-manipulation ved hjælp af moderne JavaScript-mønstre.
Opgave: Opret en forbedret version af displayCarbonUsage-funktionen, der inkluderer: 1) En genforsøgsmekanisme for mislykkede API-kald med eksponentiel backoff, 2) Inputvalidering for regionskoden før API-kaldet, 3) En indlæsningsanimation med statusindikatorer, 4) Caching af API-svar i localStorage med udløbstidsstempler (cache i 30 minutter), og 5) En funktion til at vise historiske data fra tidligere API-kald. Tilføj også korrekte TypeScript-stil JSDoc-kommentarer for at dokumentere alle funktionsparametre og returtyper.
Læs mere om agent mode her.
🚀 Udfordring
Udvid din forståelse af API'er ved at udforske de mange browserbaserede API'er, der er tilgængelige for webudvikling. Vælg en af disse browser-API'er og byg en lille demonstration:
- Geolocation API - Få brugerens aktuelle placering
- Notification API - Send desktop-notifikationer
- HTML Drag and Drop API - Opret interaktive trækgrænseflader
- Web Storage API - Avancerede teknikker til lokal lagring
- Fetch API - Moderne alternativ til XMLHttpRequest
Forskningsspørgsmål at overveje:
- Hvilke reelle problemer løser denne API?
- Hvordan håndterer API'en fejl og kanttilfælde?
- Hvilke sikkerhedsovervejelser findes der ved brug af denne API?
- Hvor bredt understøttes denne API på tværs af forskellige browsere?
Efter din forskning, identificer hvilke egenskaber der gør en API udviklervenlig og pålidelig.
Quiz efter forelæsning
Gennemgang & Selvstudie
Du har lært om LocalStorage og API'er i denne lektion, begge meget nyttige for den professionelle webudvikler. Kan du tænke over, hvordan disse to ting arbejder sammen? Overvej, hvordan du ville designe en hjemmeside, der gemmer elementer til brug af en API.
Opgave
Ansvarsfraskrivelse:
Dette dokument er blevet oversat ved hjælp af AI-oversættelsestjenesten Co-op Translator. Selvom vi bestræber os på nøjagtighed, skal du være opmærksom på, at automatiserede oversættelser kan indeholde fejl eller unøjagtigheder. Det originale dokument på dets oprindelige sprog bør betragtes som den autoritative kilde. For kritisk information anbefales professionel menneskelig oversættelse. Vi er ikke ansvarlige for eventuelle misforståelser eller fejltolkninger, der opstår som følge af brugen af denne oversættelse.

