Javascript JSON fetch async await

In Web-Anwendungen ist Javascript Fetch die bevorzugte Technik, um Daten vom Server anzugreifen. Als Netzwerkanwendung ist Fetch von Haus aus ein asynchroner Prozess (Netzwerk dauert immer etwas), aber promise und await async sind die Techniken für den synchronisierten Umgang mit fetch.

Javascript JSON Arrays

Fetch mit Callback

Ein Callback ist eine Funktion, die nach Abschluss einer asynchronen Operation aufgerufen wird. fetch() unterstützt keine echten Callbacks wie alte APIs (z. B. fs.readFile(path, callback)).

fetch(url, callback); // ❌ funktioniert NICHT

Viele Entwickler haben eigene Callback-Wrapper gebaut, weil die gesamte ältere Web-Welt (Ajax, jQuery, Node.js) traditionell Callbacks nutzte. Die Funktion wird direkt als Argument übergeben.

function fetchData(url, callback) {
	fetch(url)
		.then(response => response.json())
		.then(data => callback(null, data))
		.catch(error => callback(error));
}

fetchData('books.json', (err, data) => {
	if (err) {
		console.error('Fehler:', err);
	} else {
		console.log('Buchdaten:', data);
	}
});

Ein callback als Lösung taugt nur für sehr kleine Aufgaben, aber führt schnell zur Callback-Hölle, wenn viele verschachtelte asynchrone Operationen durchgeführt werden (z.B. Lesen einer weiteren Datei bei einem Erfolgt der initialen Aufgabe). Die Fehlerbehandlung wird schwierig. Dieser Lösungsansatz wird heute kaum noch für fetch genutzt – nur für alte APIs oder sehr einfache, einmalige asynchrone Operationen.

Fetch mit Promise

response.json() ist eine Methode des Response-Objekts, die ein JSON-Objekt aus der Antwort zieht. Die Methode gibt ein Promise zurück, also muss await response.json() auf das JSON warten.

Ein Promise ist ein Objekt, das den zukünftigen Wert einer asynchronen Operation repräsentiert. .then() und .catch() werden benutzt, um auf das Promise zu reagieren.

fetch('books.json')
	.then(response => response.json())
	.then(data => {
		console.log('Promise-Daten:', data);
	})
	.catch(error => {
		console.error('Fehler:', error);
});

.then() und .catch() vermeiden die Callback-Hölle und der Ansatz besser lesbar als pure Callbacks. Mehrere asynchrone Operationen lassen sich einfach verketten, aber bei komplexen Abläufen kommt es immer noch zu tiefen Verschachtelung.

response.json()
gibt ein JSON-Objekt zurück
response.text()
gibt reinen Text zurück
response.formData()
gibt FormData zurück
response.blob()
gibt ein Blob zurück (eine Art Datei-Objekt oder RAW-Daten)
response.arrayBuffer()()
gibt ein ArrayBuffer zurück (Binärdaten)

Promise ist eine gute Lösung, wenn mehrere asynchrone Operationen verkettet werden müssen, ohne sofort async/await zu verwenden. Ideal für Library-Code oder kurze Ketten von Operationen.

fetch async/await

async/await ist eine Schicht »syntaktischer Zucker« über Promises und lässt asynchronen Code wie synchronen aussehen.

async function getData() {
	try {
		const response = await fetch('books.json');
		const data = await response.json();
		console.log('Async Await Daten:', data);
		
		const booksEl = document.querySelector("#books");
		
		data.forEach(buch => {
			booksEl.innerHTML += `${buch.titel} – ${buch.autor}<br>`;
		});
		
	} catch (error) {
		console.error('Fehler:', error);
	}
}

getData();

Da entsteht ein gut lesbar Code, besonders bei vielen aufeinanderfolgenden asynchronen Operationen. Die Fehlerbehandlung wird mit try/catch wie bei synchronem Code ausgeführt. Aber die Funktion muss async sein ( sie muss selbst ein Promise zurückgeben!).

Insgesamt ist das heute fast immer die erste Wahl für moderne JavaScript-Projekte – besonders bei komplexen Abläufen.

callback, Promise, async/await

Technik Lesbarkeit Verkettung mehrerer async-Aufrufe Fehlerbehandlung Typische Nutzung
Callback schlecht schwierig umständlich alte APIs, sehr kleine Aufgaben
Promise mittel gut einfach .catch kurze async-Ketten, Library-Code
async/await sehr gut sehr gut wie synchron moderne JS-Entwicklung, komplexe Abläufe

Fetch Error

Gäbe es die JSON-Datei books.json im Beispiel oben nicht, würde … nichts … passieren. Nichts – weder eine Fehlermeldung in der Console noch ein Fehler 404 oder ein Serverfehler.

Aus der Sicht von Fetch ist der HTTP-Request durchgeführt. Fertig. Nur wenn der Request nicht ausgeführt werden konnte, weil z.B. die Verbindung zum Server nicht hergestellt werden konnte.

Das altbekannte response.ok des HTTP-Requests trennt einen erfolgreichen on einem misslungenen HTTP-Request.

async function missingBooks () {
	const response = await fetch('/missing');
	if (!response.ok) {
		const message = `Voll daneben: ${response.status}`;
		throw new Error(message);
	}
	const books = await response.json();
	return books;
}

missingBooks().catch(error => {
	error.message;
});
Failed to load resource: the server responded with a status of 404 () /missing

Warten auf mehrere Requests

In vielen Situationen können Daten von mehr als einem Endpunkt erforderlich sein. Wenn Daten von mehreren Endpunkten benötigt werden, gibt es mehrere Strategien, je nachdem, ob die Requests parallel oder seriell ausgeführt werden sollen.

1. Seriell (nacheinander)

Wartet, bis der erste Request abgeschlossen ist, bevor der zweite startet. Kann nötig sein, wenn ein Request von den Ergebnissen des vorherigen abhängt. Mit async/await:

async function fetchMultiple() {
  try {
    const response1 = await fetch('books.json');
    const data1 = await response1.json();

    const response2 = await fetch('booktitles.json');
    const data2 = await response2.json();

    console.log('Multi Data1:', data1);
    console.log('Multi Data2:', data2);
  } catch (error) {
    console.error('Fehler:', error);
  }
}

fetchMultiple();

Die Requests laufen nacheinander, die serielle Ausführung dauert also länger.

2. Parallele (gleichzeitige) Ausführung

Wenn die Requests unabhängig voneinander sind, lohnt sich parallel, um Zeit zu sparen. Mit Promise.all:

await Promise.all([...]) setzt parallele Fetch-Requests in Gang und wartet, bis alle Anfragen erfüllt wurden.

async function fetchBooks () {
	const [books, titles] = await Promise.all(
		[
			fetch ("books.json"),
			fetch ("booktitles.json")
		]
	);
	
	const countUni = await books.json();
	const countAll = await titles.json();
	return [countUni, countAll];
}

fetchBooks ().then (([countUni, countAll]) => {
	countUni;
	countAll;
	console.log (countUni.length);
	console.log (countAll.length);
	
}).catch (error => {
	//
})

Beide Requests starten gleichzeitig, so dass die Aufgabe schneller abgehandelt ist. Ein Fehler in einem Request wird sofort aufgefangen.

3. Promise-Ketten Variante (ohne async/await)

Promise.all([
  fetch('books.json').then(res => res.json()),
  fetch('booktitlese.json').then(res => res.json())
])
.then(([data1, data2]) => {
  console.log('Data1:', data1);
  console.log('Data2:', data2);
})
.catch(error => console.error('Fehler:', error));

Promise.all ist auch die Lösung für parallele Requests. .then() funktioniert genauso, nur syntaktisch etwas länger.

Suchen auf mediaevent.de