JavaScript: Asynchrones JavaScript und fetch

Asynchrones JavaScript

Asynchrones JavaScript

manche Aufgaben in JavaScript können gleichzeitig laufen (insbesondere Aufgaben bezüglich Input / Output):

  • Netzwerkanfragen
  • Lesen / Schreiben von Dateien in node.js
  • Timer
  • ...

Tools für asynchrones JavaScript

  • callbacks, promises, async / await: für parallels Input / Output
  • (Web) Worker: für Parallelisierung von CPU-intensiven Aufgaben (JavaScript Code läuft tatsächlich parallel)

Asynchrones JavaScript

  • callbacks: traditionelle Möglichkeit, um asynchrone Anfragen zu bearbeiten
  • promises und .then()
  • promises und async / await

Asynchrones JavaScript

Möglichkeiten, um Netzwerkanfragen zu machen:

  • fetch (Promises)
  • axios (Promises)
  • jQuery
  • XMLHttpRequest

Asynchrones JavaScript

Beispiel: Anfragen mit axios (await), axios (then) und jQuery (callback):

const res = await axios(url);
console.log(res.data);
axios(url).then((res) => console.log(res.data));
jquery.getJSON(url, (data) => console.log(data));

Fetch Grundlagen

Fetch Grundlagen

Beispiel, das in der Browserkonsole ausgeführt werden kann:

// request a URL and wait for the response header
res = await fetch(
  'https://jsonplaceholder.typicode.com/todos'
);

// wait for the response body and read it as JSON data
content = await res.json();

console.log(content);

Fetch Grundlagen

example that can be executed in the browser console with any open website:

// request the current URL
res = await fetch('/');

// wait for the response body and read its text content
content = await res.text();

console.log(content);

Asynchrone Funktionen

Asynchrone Funktionen

Funktionen, die Input- / Output-Funktinalität beinhalten, werden oft als asynchrone Funktionen definiert.

Asynchrone Funktionen können parallel zu anderem Code ausgeführt werden - z.B. um mehrere Dateien parallel über das Netzwerk zu laden

Asynchrone Funktionen

Definieren einer asynchronen Funktion:

async function loadTodo(id) {
  const res = await fetch(
    `https://jsonplaceholder.typicode.com/todos/${id}`
  );
  const data = await res.json();
  return data;
}

Asynchrone Funktionen

die asynchrone Funktion mehrfach parallel ausführen (Requests können in den Browser Devtools beobachtet werden)

for (let i = 0; i < 10; i++) {
  loadTodo(i);
}

Fetch Optionen

Fetch Optionen

Beispiel für einen fetch-Aufruf mit Optionen:

fetch(url, {
  method: 'POST',
  cache: 'no-cache',
  body: '{"text": "learn fetch"}',
  headers: { 'content-type': 'application/json' },
});

Fetch und Fehlerbehandlung

Fehlerbehandlung

Verschiedene Fehler können beim Fetch auftreten:

  • Browser ist offline (keine Antwort)
  • Server antwortet mit 404 oder ähnlicher Meldung
  • Antwort ist leer oder beinhaltet etwas anderes als text

Fehlerbehandlung: Überprüfen des Status

Standardmäßig wird eine Antwort mit einem Fehlercode (z.B. 404 oder 500) auch als Erfolg angesehen.

const fetchTodos = async () => {
  const res = await fetch(
    'https://jsonplaceholder.typicode.com/todos'
  );
  if (!res.ok) {
    throw new Error(res.statusText);
  }
  const todos = await res.json();
  return todos;
};

Promises

Promises

Promise: JavaScript-Klasse, die zukünftige Resultate repräsentiert

werden intern verwendet, wenn async / await eingesetzt werden

Promises

wir können auf Promises zugreifen, wenn wir "vergessen", auf ein asynchrones Resultat zu warten:

// a will be a promise
const a = fetch('...');

// b will be the actual result
const b = await a;

Promises

Beispiel aus der echten Welt:

Wir bestellen bei einem Fast-Food-Restaurant und erhalten folgenden Bon:

Bestellung #42:

- Cheeseburger
- kleine Pommes

Die Bestellung wird - sobald bereit - zu Ihrem Tisch gebracht.

Der Bon ist ein "Promise" - eine Repräsentation eines zukünftigen Ergebnisses

Promises

warten auf das resolven eines Promises:

  • .then()
  • await

Promises fortgeschritten

Eigene Promises

Promise, die nach 1 Sekunde entweder mit hello antwortet oder nicht erfolgreich ist

const getReply = new Promise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve('hello');
    } else {
      reject('no access');
    }
  }, 1000);
});

Promise.all

Erstellen eines Promise, das resolved wird, wenn mehere asynchrone Tasks abgeschlossen sind:

const fetchJson = async (url) => {
  const res = await fetch(url);
  return await res.json();
};

const [users, todos] = await Promise.all([
  fetchJson('https://jsonplaceholder.typicode.com/users'),
  fetchJson('https://jsonplaceholder.typicode.com/todos'),
]);

Promise.race

Das erste erfolgreiche Promise als Resultat verwenden:

const anyTodo = await Promise.race([
  fetchJson('https://jsonplaceholder.typicode.com/todos/1'),
  fetchJson('https://jsonplaceholder.typicode.com/todos/2'),
  fetchJson('https://jsonplaceholder.typicode.com/todos/3'),
]);

Ãœbungen

Ãœbungen

Axios

Axios

verbreitete Library mit mehr Funktionalität / einfacherem Interface als fetch

Axios

JSON Daten laden:

const todos = await axios(
  'https://jsonplaceholder.typicode.com/todos'
);

Status Codes in Axios

Standardverhalten:

  • Status Codes im 200er-Bereich: Erfolgreiches Promise
  • Status Codes im 400er- und 500er-Bereich: Promise wird zurückgewiesen

Axios fortgeschritten

Globale Defaults

Beispiele:

axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] =
  'application/x-www-form-urlencoded';

Eigene Instanzen und Defaults

const todosAxios = axios.create({
  baseURL: 'https://jsonplaceholder.typicode.com/todos',
  timeout: 2000,
});

todosAxios.get('/').then(console.log);
todosAxios.get('/1').then(console.log);

Interceptors

Interceptors sind Middleware, die beim Senden / Empfangen von Daten ausgelöst wird

const requestLogger = requestConfig => {
  console.log('sending request', requestConfig);
  return requestConfig;
};
todosAxios.interceptors.request.use(requestLogger);
const responseLogger = response => {
  console.log('received response', response);
  return response;
};
todosAxios.interceptors.request.use(responseLogger);