Utmaningar
Nedan finns sex frågor om att lagra data i webbläsaren. Frågorna bygger på veckans artiklar Lagring i webbläsaren och Web Storage. Den sista frågan bygger på IndexedDB, som är en orientering.
Varje fråga har ett antal alternativ att välja bland. Klicka på “Visa lösning” för att se svaret och förklaringen.
Om du är osäker kan du alltid testa i webbläsarens konsol själv eller ta upp frågan på en handledning.
Fråga 14-01: Vilken lagring?
Section titled “Fråga 14-01: Vilken lagring?”En applikation ska komma ihåg om användaren har valt mörkt eller ljust tema, också nästa gång användaren besöker sidan. Valet behövs bara av JavaScript-koden som byter tema. Var passar det bäst att spara det?
- I en cookie.
- I
localStorage. - I
sessionStorage. - I IndexedDB.
Lösningsförslag
Section titled “Lösningsförslag”Svaret är alternativ 2. Ett litet värde som bara koden på sidan behöver, och som ska ligga kvar, är
precis vad localStorage är till för.
En cookie skulle skickas med i varje förfrågan till servern, som inte har någon nytta av den.
sessionStorage försvinner när fliken stängs, så valet skulle vara borta nästa besök. IndexedDB
skulle fungera, men är ett asynkront och betydligt krångligare API för ett enda värde.
Fråga 14-02: Samma lagring?
Section titled “Fråga 14-02: Samma lagring?”Vilka av de här sidorna delar på samma localStorage?
http://localhost:5173/ochhttp://localhost:5173/settingshttp://localhost:5173/ochhttp://localhost:4173/http://localhost:5173/ochhttp://127.0.0.1:5173/https://example.com/ochhttp://example.com/
Lösningsförslag
Section titled “Lösningsförslag”Svaret är alternativ 1. Lagringen delas per origin, alltså schema, värdnamn och port. Sökvägen ingår
inte, så alla sidor på http://localhost:5173 delar på samma lagring.
I alternativ 2 skiljer porten, i alternativ 3 värdnamnet och i alternativ 4 schemat. Det är tre olika origins med var sin lagring, även om två av dem pekar på samma dator och två på samma webbplats.
Fråga 14-03: Vad skrivs ut?
Section titled “Fråga 14-03: Vad skrivs ut?”localStorage.setItem('quiz:time', 42)
const time = localStorage.getItem('quiz:time')console.log(time + 8)50'428'NaN- Ett
TypeErrorkastas, eftersomsetItem()bara tar emot strängar.
Lösningsförslag
Section titled “Lösningsförslag”Svaret är alternativ 2. Web Storage lagrar bara strängar, och setItem() gör om talet till strängen
'42' utan att säga något. getItem() ger tillbaka strängen, och '42' + 8 slår ihop strängarna
till '428'. Gör om värdet till ett tal när du läser det: Number(localStorage.getItem('quiz:time')).
Fråga 14-04: Första gången
Section titled “Fråga 14-04: Första gången”const scores = JSON.parse(localStorage.getItem('quiz:scores'))scores.push({ nickname: 'Ada', time: 31.4 })Koden körs första gången, när inget har sparats under quiz:scores. Vad händer?
scoresblir en tom array, och resultatet läggs till.JSON.parse()kastar ettSyntaxError.scoresblirnull, ochscores.push()kastar ettTypeError.getItem()kastar ett fel, eftersom nyckeln inte finns.
Lösningsförslag
Section titled “Lösningsförslag”Svaret är alternativ 3. getItem() ger null när nyckeln saknas, utan fel. JSON.parse(null)
ger också null, eftersom null görs om till strängen 'null', som är giltig JSON. Felet kommer
först på nästa rad, när push() anropas på null.
Ge ett standardvärde, och kontrollera gärna att det sparade verkligen är en array:
const saved = JSON.parse(localStorage.getItem('quiz:scores'))const scores = Array.isArray(saved) ? saved : []Kan det sparade vara ogiltig JSON, till exempel efter att någon ändrat det i utvecklarverktygen, behövs
också try och catch runt JSON.parse().
Fråga 14-05: Var ska topplistan sparas?
Section titled “Fråga 14-05: Var ska topplistan sparas?”En applikation består av komponenterna quiz-app, som orkestrerar, och leaderboard, som visar
topplistan. Var hör koden som läser och skriver topplistan i localStorage hemma?
- I
leaderboard, eftersom det är den som visar topplistan. - I
quiz-app, eller i en modul somquiz-appanvänder.leaderboardfår listan via en metod. - I
quiz-app, som skickar listan tillleaderboardsom JSON i ett attribut. - Både
quiz-appochleaderboardläser själva frånlocalStorage, så att de alltid har samma lista.
Lösningsförslag
Section titled “Lösningsförslag”Svaret är alternativ 2. Att spara och läsa är ett beslut om applikationen, och det fattas av den som
orkestrerar. leaderboard visar den lista den får, och går då att använda med en lista från en
server, från en fil eller från ett test.
Alternativ 1 och 4 gör leaderboard beroende av en viss nyckel i localStorage, och i alternativ 4
finns kunskapen om lagringen dessutom på två ställen. Alternativ 3 skickar en array som en sträng i ett
attribut. Attribut är strängar, och en array skickas med en metod, som showScores().
Fråga 14-06: Transaktionen
Section titled “Fråga 14-06: Transaktionen”Den här frågan bygger på artikeln om IndexedDB, som är en orientering.
const store = database.transaction('scores', 'readwrite').objectStore('scores')
const response = await fetch('https://api.example.com/flags/se')const flag = await response.blob()
store.add({ nickname: 'Ada', time: 31.4, flag })Vad händer på sista raden?
- Posten sparas, eftersom transaktionen väntar tills
add()anropas. - Posten sparas, men utan
flag, som inte går att lagra i IndexedDB. - Ett
TransactionInactiveErrorkastas, eftersom transaktionen redan har avslutats. - Koden väntar tills föregående transaktion är klar och sparar sedan posten.
Lösningsförslag
Section titled “Lösningsförslag”Svaret är alternativ 3. En transaktion avslutas av sig själv när den inte har några pågående anrop
och koden lämnar tillbaka kontrollen till händelseloopen. Det händer vid await fetch(), och när
add() till sist anropas finns ingen aktiv transaktion.
Hämta allt du behöver först, och skapa transaktionen när du direkt kan använda den. Alternativ 2
stämmer inte heller: IndexedDB kan lagra en Blob, till skillnad från Web Storage.