Översikt
Asynkron programmering är centralt i modern webbutveckling med JavaScript. Denna vecka tittar du på vad det innebär och tillämpar det där det är som viktigast, vid nätverksanrop. Information om veckans upplägg annonseras löpande i kursens Zulip-kanal.
Stödjande inspelningar
Section titled “Stödjande inspelningar”Ett dataöverföringsformat, inte ett programspråk
Section titled “Ett dataöverföringsformat, inte ett programspråk”JSON (JavaScript Object Notation) är det format två datorer använder för att skicka strukturerad data mellan sig – upptäckt (inte uppfunnet, enligt honom själv) av Douglas Crockford för omkring femton år sedan och sedan dess en helt öppen standard (RFC 4627, beskriven på json.org). Filändelsen är .json, MIME-typen application/json.
Det närmaste släktingen är XML, som delar HTML:s grundprinciper (taggar, element, attribut) men blir pratigt att skriva. JSON:s styrka är att det bryts ner till det mest grundläggande alla programspråk redan hanterar – tal, strängar, booleaner, samlingar, objekt – istället för att försöka stödja allt som finns i alla språk. Resultatet är ett format som i praktiken bara är text, vilket gör det både enkelt att generera och enkelt att tolka oavsett vilket programspråk eller operativsystem som sitter i andra änden.
Syntax
Section titled “Syntax”{ "name": "Ellen Nu", "city": "Kalmar", "age": 24, "registered": true}Skillnaden mot ett vanligt JavaScript-objektlitteral: alla nycklar måste ha dubbla citationstecken, till skillnad från JavaScript där nyckelnamn utan specialtecken kan skrivas utan citationstecken. Anledningen är att JSON ska fungera i språk där ett ord som är giltigt som nyckel i JavaScript kan råka vara ett reserverat ord i något annat språk – att alltid citera nycklar som strängar undviker den kollisionen helt. Tal skrivs utan citationstecken, booleaner (true/false) likaså. Giltiga JSON-datatyper är string, number, boolean, null, object och array – arrayer skrivs exakt som i JavaScript, bara med JSON-objekt eller andra värden som innehåll.
Var man stöter på det
Section titled “Var man stöter på det”Två vanliga sammanhang: konfigurationsfiler (det är därför package.json heter just .json – rent förklaringsmässigt en konfigurationsfil för npm) och, betydligt vanligare, svar från API-anrop. Anropar man ett webb-API idag är det närmast standard att få tillbaka JSON – XML förekommer fortfarande men är sällsynt utan motsvarande JSON-alternativ. Rådata från ett API-anrop kommer som en enda lång textrad utan radbrytningar (för att inte slösa bandbredd på formattering); verktyg som webbläsarens egen JSON-preview i nätverksfliken eller fristående validerare (JSONLint och liknande) formaterar om den till läsbar form. Att skriva JSON för hand är sällsynt – det är i praktiken något man tar emot, inte något man skapar direkt.
Från text till JavaScript-objekt och tillbaka
Section titled “Från text till JavaScript-objekt och tillbaka”const json = JSON.stringify(students) // JavaScript -> JSON-text (serialisering)const parsed = JSON.parse(json) // JSON-text -> JavaScript-objektJSON.stringify serialiserar ett JavaScript-värde till en textsträng – bra namngivning här spelar roll: variabeln som håller resultatet av stringify bör beskriva att den är JSON-text, medan variabeln som håller resultatet av parse bör namnges efter vad datan faktiskt föreställer (students, inte json) snarare än efter formatet den kom ifrån. Bara egentliga data-egenskaper (primitiver, arrayer, objekt) serialiseras – metoder/funktioner på ett objekt tas helt enkelt bort ur resultatet, de orsakar inget fel.
Statiska .json-filer kan också läsas in direkt med import i en modul (import students from './students.json'), men det är (2021) ett webbläsarspecifikt beteende – stöd i Node.js var vid tidpunkten fortfarande experimentellt bakom flaggor. Kontrollera aktuellt läge om detta är relevant, då stödet för JSON-import i Node har fortsatt utvecklas sedan dess.
JSON.parse är farligare än JSON.stringify
Section titled “JSON.parse är farligare än JSON.stringify”JSON.stringify misslyckas i praktiken nästan aldrig – körs den på vanlig JavaScript-data blir resultatet alltid en giltig sträng. JSON.parse däremot bör alltid omges av try/catch så fort datan kommer utifrån och inte är fullt kontrollerad. Ett vanligt scenario: API:et som anropas har kraschat och svarar med en vanlig HTML-felsida (till exempel en 404-sida) istället för JSON – JSON.parse får då text den inte kan tolka och kastar ett undantag. Kommer datan från en egen, känd fil (som ett import) är risken förstås mindre, men så fort data hämtas över nätverket bör man räkna med att tolkningen kan misslyckas.
Synkront – och därmed blockerande
Section titled “Synkront – och därmed blockerande”Både JSON.stringify och JSON.parse är synkrona funktionsanrop: de kör klart hela sitt arbete innan nästa rad kod exekveras, oavsett hur stor datamängden är. I de allra flesta fall spelar det ingen roll, men principiellt blockerar de – en mycket stor textsträng tar mätbart längre tid att parsa, och under den tiden står resten av programmet still. I praktiken är det sällan parse/stringify själva som blir flaskhalsen, utan snarare nätverksanropet som hämtat datan i första hand – ett tecken på att man kanske bör hämta data i mindre bitar (paginering) istället för allt på en gång. Detta är också den naturliga övergången till nästa ämne: eftersom nätverksanrop tar tid (även små anrop tar tiotals millisekunder) går de inte att göra synkront på samma sätt – de kräver en asynkron modell.
Kommunikation från Webbläsaren
Section titled “Kommunikation från Webbläsaren”Varför behöver webbläsaren prata med servern efter att sidan laddats?
Section titled “Varför behöver webbläsaren prata med servern efter att sidan laddats?”En traditionell webbsida kräver en omladdning för att visa ny information – det är därför gamla kurshemsidor (byggda med t.ex. Gatsby) behöver laddas om manuellt för att visa en ny föreläsning. En applikation som Slack fungerar annorlunda: nya meddelanden dyker upp utan att sidan laddas om, vilket kräver att klienten hela tiden kommunicerar med en server i bakgrunden och hämtar (eller tar emot) ny data. Webbläsaren har flera API:er för den typen av kommunikation – XMLHttpRequest (den äldre, ursprungliga tekniken), fetch (den moderna efterträdaren, kursens fokus framöver), WebSocket (för tvåvägs realtidskommunikation, se ett senare avsnitt) och dynamiska import()-anrop för att ladda JavaScript-kod efter att sidan redan startat.
HTTP: protokollet bakom kommunikationen
Section titled “HTTP: protokollet bakom kommunikationen”HTTP (Hypertext Transfer Protocol) är samma protokoll som används för att hämta den allra första index.html, och det är också protokollet fetch och XMLHttpRequest bygger på för att prata med en server. Standarden definierar ett antal metoder (verb): GET och POST är de vanligaste och de enda som stöds direkt av HTML-formulär (<form method="...">), men det finns fler – PUT för att helt ersätta en befintlig resurs, PATCH för att uppdatera den partiellt, och DELETE för att ta bort den. Att skicka rätt verb till en server är ett sätt att slippa uppfinna ett eget litet protokoll för varje typ av operation – servern förväntas tolka en DELETE-förfrågan som “ta bort den här resursen” utan vidare förklaring.
GET /theserverpage/?user=Ellen&message=Hello HTTP/1.1Host: lnuserver.seVid en GET skickas eventuell data som en query-sträng i URL:en (samma sätt som ett HTML-formulär med method="get" bygger sin URL). Vid en POST skickas datan istället i förfrågans body:
POST /theserverpage/ HTTP/1.1Host: lnuserver.seContent-Length: 24
user=Ellen&message=HelloPOST är inte i sig en säker transportmetod – all okrypterad HTTP-trafik kan avlyssnas av den som sitter mellan klient och server. Skillnaden mot GET är enbart att datan inte hamnar synlig i URL:en (t.ex. i webbläsarens historik eller om någon tittar över axeln), inte att den blir krypterad eller skyddad. Riktig säkerhet kräver HTTPS, oavsett vilket HTTP-verb som används.
Statuskoder – lita aldrig blint på att “det gick igenom”
Section titled “Statuskoder – lita aldrig blint på att “det gick igenom””Serverns svar innehåller alltid en statuskod, och den säger mer om vad som faktiskt hände än innehållet i svaret gör. Grovt indelat:
- 2xx – lyckades (
200 OKär standardfallet) - 3xx – omdirigering (
301 Moved Permanently,307 Temporary Redirect) - 4xx – felet ligger hos klienten (
400 Bad Request,401 Unauthorized,403 Forbidden,404 Not Found) - 5xx – felet ligger hos servern (
500 Internal Server Error,503 Service Unavailable)
Ur ett API-designperspektiv är detta ett argument för att vara frikostig med rätt statuskoder när man själv bygger en server längre fram i utbildningen – utan att för den sakens skull läcka onödig intern information i felmeddelanden (t.ex. i ett 500-svar), vilket är värdefull information för den som vill attackera applikationen.
AJAX: teknikens historia
Section titled “AJAX: teknikens historia”Termen AJAX (Asynchronous JavaScript and XML) myntades 2005 av Jesse James Garrett i en inflytelserik artikel som beskrev en teknik Microsoft redan byggt in i Internet Explorer 5 (1999) – ursprungligen som en proprietär ActiveX-komponent, XMLHttpRequest. Fram till dess var webben i praktiken statisk: dynamiskt innehåll byggdes med hackiga lösningar som periodiskt omladdade <iframe>-element, Flash eller Java-applets. Mozilla, Safari och Opera implementerade XMLHttpRequest som en öppen standard runt millennieskiftet, Microsoft följde efter i Internet Explorer 7 (2006), och artikeln 2005 fick utvecklare i stort att inse att webbapplikationer kunde bygga vidare på den här tekniken – något som i förlängningen bidrog till att JavaScript gick från att ses som ett marginellt “blinkande text”-språk till dagens ställning, och en bidragande orsak till att Flash så småningom blev överflödigt.
Runt 2015 fick webbläsarna brett stöd för fetch, ett modernare och enklare API för samma typ av nätverkskommunikation. XMLHttpRequest finns fortfarande kvar och fungerar, men fetch är det API kursen fokuserar på framöver.
Asynkron programmering - Introduktion
Section titled “Asynkron programmering - Introduktion”Synkront och asynkront – inget nytt koncept
Section titled “Synkront och asynkront – inget nytt koncept”Skillnaden mellan synkront och asynkront är inte unik för programmering. Ett videosamtal är synkront: båda parter är närvarande och svarar varandra i realtid. Att titta på en inspelad föreläsning är asynkront: den kan pausas, skjutas upp och återupptas helt oberoende av när den spelades in. Mejl och chattmeddelanden räknas på samma sätt som asynkrona – man väljer själv när man svarar – medan ett telefonsamtal är synkront, det förväntas ett svar direkt. Samma distinktion gäller kod: synkron kod körs i strikt sekvens, en sats i taget, och väntar in varje anrop innan nästa körs; asynkron kod skjuter upp delar av arbetet till senare, utan att blockera resten av programmet under tiden.
En ny pusselbit: webbläsarens API:er
Section titled “En ny pusselbit: webbläsarens API:er”Utöver stacken och kön (task queue) finns en tredje del i bilden: webbläsaren har inbyggda API:er som kan utföra arbete – till exempel nätverksanrop – helt utanför vår egen stack. Det är den resursen som gör asynkron kod möjlig: webbläsaren kan jobba i bakgrunden med sådant som tar tid, och lägga en task i kön först när arbetet är klart.
Synkront nätverksanrop – den gamla, förbjudna vägen
Section titled “Synkront nätverksanrop – den gamla, förbjudna vägen”const req = new window.XMLHttpRequest()req.open('GET', 'students.json', false) // false = synkrontreq.send()const json = JSON.parse(req.responseText)XMLHttpRequest är den ursprungliga tekniken för nätverksanrop i webbläsaren – inte något som används aktivt i den här kursen, men värt att känna igen om man stöter på det i äldre kod. Sätts tredje argumentet till open till false blir anropet synkront: send() returnerar först när svaret faktiskt har kommit tillbaka, vilket kan ta allt från några millisekunder till flera sekunder. Under hela den tiden står webbläsarens gränssnitt still – inget annat kan hända. Synkrona XMLHttpRequest-anrop är numera förbjudna i moderna webbläsare av precis den anledningen.
Asynkront nätverksanrop – callback-mönstret
Section titled “Asynkront nätverksanrop – callback-mönstret”const req = new window.XMLHttpRequest()req.addEventListener('load', function () { console.log(req.responseText)})req.open('GET', 'students.json')req.send()Här registreras en händelselyssnare för load innan send() anropas. send() returnerar nu omedelbart – allt den egentligen gör är att tala om för webbläsaren vad som ska hämtas, sedan är stacken fri igen. Webbläsaren sköter själva nätverksanropet i bakgrunden (i den nya API-rutan, inte på stacken), och när svaret kommer tillbaka läggs en task i kön som anropar den registrerade funktionen. Det här är samma callback-mönster som händelselyssnare i allmänhet – ingenting konstigare än att vänta på att en användare klickar på en knapp.
En viktig garanti: kod som redan ligger och kör på stacken körs alltid klart innan någon köad callback-task får köra. Det spelar ingen roll om svaret kommer tillbaka blixtsnabbt (till exempel för att webbläsaren cachat filen) – en callback kan aldrig avbryta pågående synkron kod, den måste vänta tills stacken är tom. Det man däremot förlorar med asynkron kod är den självklara läsordningen: koden exekveras inte längre uppifrån och ned i en enda följd, utan i den ordning som stacken respektive kön faktiskt hanterar den.
Effekten på webbläsarens gränssnitt
Section titled “Effekten på webbläsarens gränssnitt”Ritas de två varianterna upp på en tidslinje syns skillnaden tydligt: med blockerande (synkron) kod upptas stora sammanhängande delar av tidslinjen av väntande anrop, och användargränssnittet fryser under hela den tiden. Med icke-blockerande (asynkron) kod är stacken bara upptagen en kort stund i taget – för att förbereda och skicka iväg anropet – medan resten av tiden är fri för annan kod (och för webbläsarens eget gränssnittsarbete) att köra. Flera anrop kan till och med förberedas och köras parallellt i bakgrunden på det här sättet.
JavaScript är entrådigt – webbläsaren är det inte
Section titled “JavaScript är entrådigt – webbläsaren är det inte”Att JavaScript är entrådigt syftar på att det bara finns en stack och en kö för vår egen kod – det finns bara en plats där vår kod kan exekveras åt gången. Webbläsaren själv har dock möjlighet att använda egna trådar och göra arbete parallellt i bakgrunden; som utvecklare kan man beställa den typen av arbete (nätverksanrop, timers) men inte skapa egna trådar direkt – med undantag för Web Workers, ett separat API som tas upp senare i kursen.
Detta är grunden för async/await och Promises, som byggs vidare på i nästa del.
Asynkron programmering - Promises och Async/Await
Section titled “Asynkron programmering - Promises och Async/Await”Formulär som progressive enhancement
Section titled “Formulär som progressive enhancement”Innan nätverksanrop med JavaScript tas upp på allvar är ett kort råd värt att ta med sig: bygg gärna vidare på vanliga HTML-formulär (method, action) istället för att helt ersätta dem. Ett formulär som fungerar utan JavaScript, där koden sedan läser av method/action och gör anropet i bakgrunden utan att sidan laddas om, är en robustare grund än att bygga nätverkslogiken helt frikopplad från formuläret. Lyssna på formulärets submit-händelse (form.addEventListener('submit', ...)) snarare än på ett klick på submit-knappen – ett formulär kan skickas på fler sätt än ett musklick. Och inaktivera (disable) submit-knappen så fort den klickats: annars är det lätt hänt att en användare som inte får omedelbar respons klickar igen, och igen, vilket i värsta fall kan trigga samma serveranrop flera gånger (t.ex. en dubbel beställning).
Fetch API utan async/await
Section titled “Fetch API utan async/await”fetch är webbläsarens moderna, standardiserade API för nätverksanrop – efterträdaren till XMLHttpRequest (se föregående avsnitt). Det tar en resurs som första argument och ett konfigurationsobjekt som andra – ett vanligt mönster i nyare API:er, istället för att lista många enskilda argument.
const data = { id: 54322575, name: 'Johan' }
window.fetch('http://url-to-fetch.at/path', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data)}).then(res => { // hantera svaret här}).catch(error => { // hantera fel här})fetch returnerar omedelbart ett Promise – ett löfte om att leverera ett resultat vid ett senare tillfälle (samma princip som ett banklöfte om ett lån: inte pengarna direkt, men ett löfte om att de kommer). Promiset har metoderna then (körs när löftet löser ut framgångsrikt) och catch (körs om något gick fel), vilket i grunden är samma idé som callback-mönstret fast standardiserat runt en gemensam typ. Kedjar man flera anrop efter varandra med upprepade .then() växer koden snabbt i komplexitet – ett problem som brukar kallas promise hell, samma typ av läsbarhetsproblem som callback hell för den äldre callback-stilen.
Async/await – samma sak, mycket mer läsbart
Section titled “Async/await – samma sak, mycket mer läsbart”async/await är syntax ovanpå Promises, inte en ny mekanism – koden nedan gör exakt samma sak som exemplet ovan, bara mer likt synkron kod att läsa:
async function postData () { const data = { id: 54322575, name: 'Johan' }
const res = await window.fetch('http://url-to-fetch.at/path', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) })}await kräver att koden befinner sig i en asynkron kontext – vanligtvis en funktion markerad med async framför (det går numera även att använda await direkt på modulnivå, “top-level await”, en nyhet i standarden från 2021 – men i vanliga funktioner krävs fortfarande async-nyckelordet). await pausar exekveringen av just den funktionen tills promiset löser ut, utan att blockera resten av kön – webbläsaren är fri att göra annat under tiden, precis som med alla andra köade uppgifter.
Felhantering vid await sker med vanlig try/catch runt anropet – inget nytt behövs utöver det befintliga språkkonstruktet.
Ett vanligt misstag är att glömma async framför en funktion som innehåller await. Att sätta async “för säkerhets skull” på alla metoder är dock inte att rekommendera – det signalerar till läsaren att metoden gör asynkront arbete, vilket blir missvisande om den inte faktiskt gör det. Skriv istället koden naturligt, och låt ett fel om att await bara får användas i en asynkron kontext påminna om det saknade async-nyckelordet.
Ett praktiskt exempel: sök efter tv-serier
Section titled “Ett praktiskt exempel: sök efter tv-serier”Exemplet i föreläsningen är en webbkomponent som söker fram tv-serier från ett tänkt API. Ett första sökanrop returnerar bara id:n på träffarna, och varje id behöver sedan slås upp separat för mer information:
async getShow (id) { const res = await window.fetch(`http://tv-api.se/shows/${id}`) return res.json()}
async searchUpdate (str) { const res = await window.fetch(`http://tv-api.se/shows/?q=${str}`) const data = await res.json() // { searchString: 'prison', ids: [24] } this.show = await this.getShow(data.ids[0]) // Prison Break}Notera att getShow returnerar res.json() direkt utan ett eget await framför – eftersom funktionen är async returnerar den ändå alltid ett Promise, och await this.getShow(...) i anropande kod väntar korrekt in det yttersta löftet oavsett hur många lager av Promises som ligger i vägen.
Fällan: sekventiella anrop i en loop
Section titled “Fällan: sekventiella anrop i en loop”Har sökningen flera träffar (ids: [24, 35]) räcker det inte att bara slå upp det första – samtliga behöver hämtas. Ett naturligt första försök är en vanlig loop:
this.shows = []for (const id of data.ids) { this.shows.push(await this.getShow(id))}Koden fungerar, men blir i praktiken synkron: varje await i loopen väntar in hela anropet innan nästa startar, trots att anropen inte alls är beroende av varandra. Det är samma princip som att beställa varor på nätet en produkt i taget och vänta på leverans mellan varje beställning istället för att lägga en enda samlad beställning – onödigt långsamt när arbetet lika gärna kan ske parallellt.
Parallellisera med Promise.all
Section titled “Parallellisera med Promise.all”Genom att inte awaita getShow direkt i loopen, utan istället samla ihop alla Promises i en array, kan alla anrop startas samtidigt:
async searchUpdate (str) { const res = await window.fetch(`http://tv-api.se/shows/?q=${str}`) const data = await res.json() // { searchString: 'break', ids: [24, 35] }
const showPromises = data.ids.map(id => this.getShow(id)) this.shows = await Promise.all(showPromises)}data.ids.map(id => this.getShow(id)) startar samtliga fetch-anrop direkt (webbläsaren sköter dem parallellt i bakgrunden) och returnerar en array av Promises, inte färdiga resultat – getShow är async och returnerar alltid ett Promise, oavsett om det awaitas direkt eller inte. Promise.all tar den arrayen och returnerar i sin tur ett nytt Promise som löser ut först när samtliga i arrayen är klara, med en array av alla resultat i samma ordning. Resultatet blir kod som ser nästan lika enkel ut som den sekventiella varianten, men som utnyttjar att anropen kan köras samtidigt istället för i tur och ordning.
Promise.race är en besläktad metod värd att känna till: den löser ut så fort det första av flera Promises blir klart, användbart om man bara bryr sig om det snabbaste svaret av flera möjliga källor. Den är betydligt mindre använd i praktiken än Promise.all.
Att koppla ihop det med en händelsehanterare
Section titled “Att koppla ihop det med en händelsehanterare”Själva sökningen triggas av en klickhändelse, och händelsehanteraren behöver själv vara async för att kunna awaita resultatet innan gränssnittet uppdateras:
connectedCallback () { this.#searchButton.addEventListener('click', async (event) => { await this.searchUpdate(this.#input.value) this.#updateRendering() })}Att utelämna await här skulle innebära att #updateRendering() körs innan sökresultatet faktiskt kommit tillbaka – gränssnittet skulle då visa förra sökningens resultat, och det nya resultatet skulle inte synas förrän användaren sökte igen. De flesta nyare webbläsar-API:er (Web USB, Service Workers med flera) bygger genomgående på Promises, så förståelsen för async/await är inte begränsad till nätverksanrop – den är en förutsättning för att kunna använda stora delar av plattformens moderna funktionalitet.
Cross Origin Resource Charing (CORS)
Section titled “Cross Origin Resource Charing (CORS)”En sandlåda i webbläsaren
Section titled “En sandlåda i webbläsaren”Cross-Origin Resource Sharing (CORS) är en säkerhetsmekanism inbyggd i webbläsaren, inte på servern – den finns till för att en webbsida inte fritt ska kunna göra skriptdrivna anrop mot vilken annan domän som helst. Den första GET-förfrågan en sida gör (mot huvuddokumentet) sätter sidans origin – domänen sidan anses tillhöra. Resurser som .css, bilder och typsnitt kan i regel hämtas från andra domäner utan problem (till exempel ett typsnitt eller en bild från ett CDN), men försöker JavaScript göra ett nätverksanrop (till exempel via fetch) mot en annan domän än sidans egen origin, kontrolleras det anropet av CORS.
Preflight och felmeddelandet som gömmer sig
Section titled “Preflight och felmeddelandet som gömmer sig”Innan webbläsaren släpper igenom ett sådant korsdomänanrop skickar den i praktiken en förfrågan till målservern – en preflight – och frågar om det är okej. Servern svarar med särskilda CORS-headrar (Access-Control-Allow-Origin med flera) som antingen tillåter alla, en specifik lista av domäner, eller ingen alls. Tillåter servern inte anropet blockerar webbläsaren det – och av säkerhetsskäl får JavaScript inte ens läsa ut varför anropet misslyckades. Skriptet vet bara att något gick fel, inget mer; annars skulle ett skadligt skript kunna använda felmeddelandet för att kartlägga vilka domäner och resurser som finns tillgängliga.
Felet syns bara i webbläsarens devtools-konsol, aldrig i själva JavaScript-koden, och har ett typiskt utseende att känna igen:
Failed to load ...: No 'Access-Control-Allow-Origin' header is present on therequested resource. Origin 'http://localhost:4000' is therefore not allowed access.Så fort ordet CORS dyker upp i en sådan konsolrad är det ett tecken att stanna upp: det handlar inte om ett fel i den egna koden, utan om att målservern inte tillåter anrop från den egna domänen. Om anropet fungerar eller inte beror helt på hur målservern är konfigurerad – många publika API:er (till exempel GitHub) tillåter anrop från alla domäner, medan andra bara tillåter sina egna.
Två sätt att lösa det
Section titled “Två sätt att lösa det”- Lägg till CORS-headrar på servern som anropas – fungerar bara om man själv äger och kan konfigurera den servern.
- Använd sin egen server som proxy – CORS är en begränsning i webbläsaren, inte mellan servrar. Går det inte att styra över målservern går anropet istället via den egna servern: klienten anropar den egna servern, som i sin tur (utan CORS-begränsning, eftersom serverkod inte körs i en webbläsare) anropar tredjepartsservern, hämtar datan och skickar tillbaka den till klienten.
Den andra lösningen är den vanligaste när man inte har kontroll över den externa tjänsten.
Läsanvisningar
Section titled “Läsanvisningar”Under läsanvisningar hittar du veckans kapitel som ska läsas i kurslitteraturen. Planera upp och dela upp läsningen under veckan.
Övningar
Section titled “Övningar”Under Övningsuppgifter hittar du övningsuppgifter som det är lämpligt att du arbetar med under veckan.
Handledning
Section titled “Handledning”Skicka gärna in frågor på förhand via formuläret som du når här:
Examinationsuppgift B2
Section titled “Examinationsuppgift B2”Dags att påbörja kursens andra quiz-baserade examinationsuppgift B2.
Just nätverksanrop som du går igenom denna vecka är centralt i uppgiften!
Studiefrågor
Section titled “Studiefrågor”Här är ett antal frågor som du kan försöka besvara och diskutera tillsammans med din AI-assistent. Tveka inte att lyfta någon av frågorna till handledningen för att fortsätta diskussionen med lärare och studiekamrater.
- Ge mig en kort förklaring av JSON och vilka datatype som formatet har.
- Är JSON användbart tillsammans med REST API:er?
- Hur fungerar ett REST API?
- Är Postman ett rimligt verktyg när man vill undersöka ett REST API?
- Kan man prata med ett REST API från JavaScript i en webbläsare?
- Hur ställer man in CORS på webbservern?
- Visa hur man använder fetch i webbläsaren tillsammans med async/await.
Här är en utskrift från hur det såg ut när jag diskuterade ovan frågor med min AI-assistent Ajj.
Här följer tips till hur du kan prioritera bland kursmaterialet för att komma igång med veckan.
- Titta igenom föreläsningarna. Fokusera på hur fetch fungerar tillsammans med async/await.
- Utför övningsuppgiften för att träna på fetch.
- Se till att komma igång med examinationsuppgiften B2.
