Fetch ja asynkroniset funktiot
Javascriptin normaalit funktiot suoritetaan synkronisesti eli peräkkäin. Tarjolla on kuitenkin myös asynkronisia funktioita, joita voidaan suorittaa rinnakkain. Näitä ei tällä kurssilla ole juurikaan tarvetta itse kirjoittaa, mutta joskus näitä täytyy osaa käyttää. Esim. sovelluksen hakiessa palvelimelta dataa tai lähettäessä palvelimelle dataa käytetään fetch API -rajapintaa, joka toimii asynkronisesti.
Asynkronisiin funktioihin liittyvät myös Promiset, jotka ovat objekteja, jotka "lupaavat" tekevänsä jotain. Lupaus on joko tekeillä (pending), tehty (fulfilled) tai epäonnistunut (rejected). Käytännössä tämä tarkoittaisi esim. fetch-pyynnön yhteydessä, että palvelimelle lähetetty pyyntö on vielä kesken tai palvelimelta on jo saatu vastaus tai pyyntö on epäonnistunut verkkovirheen tai muun ongelman takia. Promisen valmistumista odotellessa sovellus voi tehdä muita asioita, koska kyseessä on asynkroninen toiminta. Sovellus ei siis välttämättä jää odottamaan Promisen valmistumista vaan tähän reagoidaan vasta myöhemmin.
Promiset käsitellään joko ketjuttamalla funktioita (.then()) tai käyttämällä async/await-avainsanoja. async-sanalla esitellään funktio, joka voi toimia asynkronisesti. await-sanaa voi käyttää asyncilla esitellyssä funktiossa odottamaan promisen toteutumista ja palautusarvoa.
Esimerkki
console.log("fetch-kutsu");
fetch('https://appro.mit.jyu.fi/cgi-bin/tiea2120/vt2.cgi/') // käytetään vt2:n dataa mallina
.then( function(response) { // odotetaan promisen valmistumista ja palautetaan uusi promise eli response tekstimuodossa
console.log("saatiin response - ketjutettu fetch");
// console.log(response);
return response.text();
})
.then(function(data) { // saadaan lopulta valmis data, jolle voidaan tehdä jotain
console.log("saatiin valmis data - ketjutettu fetch")
// console.log(data);
// täällä tehdään jotain saadulle datalle
}
);
console.log("Tämä tulostuu ennen kuin fetch valmistuu");
// sama kuin edellä, mutta yksinkertaisempi toteutus async/await-avulla
// luodaan oma asynkroninen funktio
async function haeData() {
// sama fetch-kutsu kuin aiemmin, mutta nyt await jää odottamaan fetchin valmistumista
const response = await fetch('https://appro.mit.jyu.fi/cgi-bin/tiea2120/vt2.cgi/')
console.log("saatiin response - async/await-versio");
// taas sama kuin edellisessä versiossa, mutta yksinkertaisempi toteutus awaitin avulla
const data = await response.text();
console.log("saatiin data - async/away-versio");
// console.log(data);
}
console.log("kutsutaan haeData");
haeData();
console.log("tämä tulostuu ennen kuin haeData valmistuu");
Selaimen konsoliin tulostuu jotakin seuraavanlaista, mutta ei aina välttämättä juuri tässä järjestyksessä:
fetch-kutsu
Tämä tulostuu ennen kuin fetch valmistuu
kutsutaan haeData
tämä tulostuu ennen kuin haeData valmistuu
XHR GET https://appro.mit.jyu.fi/cgi-bin/tiea2120/vt2.cgi/
saatiin response - ketjutettu fetch
XHR GET https://appro.mit.jyu.fi/cgi-bin/tiea2120/vt2.cgi/
saatiin valmis data - ketjutettu fetch
saatiin response - async/await-versio
saatiin data - async/away-versio
Fetch API
fetch on periaatteessa hyvin yksinkertainen asynkroninen funktio, jolla voidaan kutsua www-palvelimelta jotakin resurssia, joka sitten saadaan käsiteltäväksi. Käytännössä fetchin käyttöä rajaa ja hankaloittaa kuitenkin selaimen tietoturva ja CORS.
Oletuksena javascript-sovellus voi pyytää resursseja vain samalta palvelimelta, josta itse sovellus on ladattu (Same-origin policy). Poikkeuksen tähän voi tehdä, jos käytössä on sopivat CORS-otsikot. CORS-otsakkeisiin ei tällä kurssilla voida vaikuttaa eikä mennä sen syvemmälle, koska nämä liittyvät www-palvelimen asetuksiin ja siten Web-palvelinohjelmointikurssille.
Fetch-pyynnön yhteydessä voidaan säätää jonkin verran asetuksia, jotka vaikuttavat esim. kuljetetaanko pyynnön mukana autentikointitietoja ja evästeitä. Fetchin asetukset ovat jo Web-palvelinohjelmointiin liittyviä, mutta käyttöliittymäohjelmoijan pitää näistä joskus mahdollisesti jotain osata muuttaa. Esim. käytetty metodi voi muuttua tilanteesta riippuen.
// oletusarvot on merkitty *-merkillä
const response = await fetch("https://foo.example", {
method: "POST", // *GET, POST, PUT, DELETE, etc.
mode: "cors", // no-cors, *cors, same-origin eli hyödynnetäänkö CORS-otsakkeita vai ei
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached eli välimuistin toiminta
credentials: "same-origin", // include, *same-origin, omit - valitse include, jos haluat kirjautumistiedot pyynnön mukaan muualle kuin same-originiin
headers: {
"Content-Type": "application/json",
// tavallisen lomakkeen ollessa kyseessä content-type on:
// 'Content-Type': 'application/x-www-form-urlencoded',
// voidaan käyttää kuitenkin myös json-muotoa kuten yllä tai
// xml-muotoa kuten text/xml tai application/xml. Erikoismuodot
// ovat kuitenkin rajatumpia kuin tavallinen lomakemuoto
},
redirect: "follow", // manual, *follow, error - mitä tehdään edelleenohjauksille
referrerPolicy: "no-referrer", // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data), // datan pitää vastata ylläolevaa "Content-Type"-otsaketta
});
Katso seuraavat:
Käyttäjien kommentit