Poznajemy lub – mam nadzieję – przypominamy sobie async i await w JavaScript oraz podstawy korzystania z tzw. fetch API. Do dzieła.
Ok funkcja async:
- Potrzebuje słowa kluczowego async, dzięki któremu może korzystać z await
- Await stosujemy przed czymś, co zwraca promise
- Do czasu, aż promise nie będzie settled, kod JS poza tą funkcją zaczyna się wykonywać
- Gdy już promise będzie settled to wartość, jaką przekazuje do resolve lub reject zostanie zapisana do zmiennej zaś kod pod await będzie się wykonywał jakby był takim then pod promise, ale zbierającym dwa callbacki (onfulfilled i onrejected) w jedno
To może jakiś przykład:
function resolveAfter2Seconds() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// Expected output: "resolved"
}
asyncCall();
Możemy jeszcze consoleloga walnąć pod asyncCall. Najpierw wywoła się calling, potem czekamy na funkcję, aż jej promise będzie settled, wtedy reszta JS poza funkcją się wykonuje, gdy promise będzie settled, to wartość przekazana do resolve LUB reject będzie znajdowała się w result.
I dalszy kod z ciała funkcji to będzie taki jakby odpowiednik then, on się zacznie wykonywać, jak promise będzie settled.
Ok, fetch API:
- przyjmuje url oraz opcjonalnie options
- zwraca promise zawierającą m.in kod odpowiedzi i takie tam
- to, co zwraca fetch ma też metody, które zwracają kolejne promise, np. metoda json zwraca body, ale trzeba na nią poczekać
Tu mamy jakiś prosty przykład z internetu fetcha bez async await traktowanego jako promise:
fetch(
'https://carbonfootprint1.p.rapidapi.com/CarbonFootprintFromCarTravel?distance=100&vehicle=SmallDieselCar',
{
method: 'GET',
headers: {
'x-rapidapi-key': 'your_api_key'
}
}
).then(response => {
console.log(response);
});
I tak możemy sobie go w React używać w useEffect (lepiej byłoby zdefiniować własną funkcję async w useEffect i ją od razu wywołać). Dodam, że tutaj autor powinien zwrócić w then response.json(), które zwraca kolejny promise, z body, do którego można podpiąć kolejny then.
Ale tak się bawić nie będziemy, od tych rzeczy mamy async await i tu mamy przykład z dobrze nam znanego githuba:
export async function fetchAvailablePlaces() {
const response = await fetch('http://localhost:3000/places');
const resData = await response.json();
if (!response.ok) {
throw new Error('Failed to fetch places');
}
return resData.places;
}
Przypomnę, nie ma znaczenia, gdzie sprawdzamy response.ok, mamy możliwość to sprawdzić już po pierwszym awaicie, ale po drugim też możemy. Fetch zwraca promise, czekamy. Metoda json obiektu response zwraca promise, czekamy.
Dalej sprawdzamy, czy odpowiedź do nas dotarła, jak tak zwracamy to, co ma pod kluczem places. Proste.
Teraz obiekt options, ciekawsze jego properties:
- method czyli metoda, domyślnie get
- signal – abortcontroller, już to znamy, robiliśmy
- keepalive – czy po zgaszeniu strony dalej request ma działać
- headers – nagłówki
- body – jak mamy inną niż get metodę to body ma znaczenie. Dodam, że do body przekazujemy w notacji JSON, notacji obiektowej, ale string, czyli mamy jakiś obiekt JS i przepuszczamy go przez JSON.stringify i umieszczamy pod body
Przykład z MDN wykorzystania body oraz headers, korzystanie z obiektu headers nie jest konieczne, może być obiekt JS, ale za to w body musimy mieć obiekt JSON, czyli obiekt w notacji obiektu JS zamieniony na string przez JSON.stringify:
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
const response = await fetch("https://example.org/post", {
method: "POST",
body: JSON.stringify({ username: "example" }),
headers: myHeaders,
});
Ok, to by było na tyle, więcej JSa oraz Reacta niedługo.