Hallo Helge,
eigentlich hast Du nur einen kleinen Fehler drin:
throw new Error(res.text());
res.text() liefert nicht den Text, sondern ein Promise für den Text. Das ist deshalb so, weil das von fetch gelieferte Promise bereits resolved, sobald der Browser die http-Header vorfindet. Der eigentliche Body ist ggf. noch gar nicht da.
Du musst den Error also mit dem werfen, was aus dem res.text() Promise herauskommt.
fetch(url) // -> Promise A
.then(response => { // then-1
if (response.ok)
return response.text(); // -> Promise E
else
return response
.text() // -> Promise F
.then(msg => throw new Error(msg)); // then-3
// -> Promise G
}) // -> Promise B
.then(text => { // then-2
...
}) // -> Promise C
.catch(error => {
...
}); // -> Promise D
Die Promise-Flut bei fetch ist nicht ganz einfach zu durchschauen. fetch liefert ein Promise A. Auf Promise A wird then-1 aufgerufen und liefert ein NEUES Promise: Promise B. Auf B wird then-2 aufgerufen, heraus kommt Promise C, und darauf wird catch aufgerufen. Auch catch liefert wieder ein Promise - aber dieses wird im Beispiel nicht weiter verwendet.
All das passiert, während der Browser gerade erst den Request zum Server schickt. Nachdem catch sein Promise D zurückgegeben hat, läuft JavaScript weiter.
Irgendwann trifft die Antwort vom Server ein und Promise A erfüllt sich (es sei denn, der Server antwortet nicht, dann wird es rejected - was auch Promise B rejected, was Promise C rejected, was den Callback bei catch() aufruft).
Wird Promise A resolved, läuft der Callback von then-1 an. Der prüft den response-Status und ruft nun response.text() auf. Daraus entsteht nun ein neues Promise E oder F, je nach Codezweig.
Im ok-Zweig wird Promise E direkt zurückgegeben, was die Erfüllung von Promise B an die Erfüllung von Promise E koppelt. Der Callback von then-2 liefert deshalb den Text, zu dem Promise E resolved wird.
Wenn response.ok nicht gesetzt ist, wird ebenfalls response.text() aufgerufen, was ein Promise F liefert, aber hierauf wird nun gleich das then-3 aufgerufen. Das ergibt ein Promise G, was aus dem then-1 zurückgegeben wird. Im Fehlerfall ist also nun der Erfolg von Promise B an den Erfolg von Promise G gekoppelt.
Das then-3 ist aber nun so geschrieben, dass es den Text von Promise F entgegen nimmt und ihn als Error wirft. Eine Exception im then-Callback führt zum Reject des Promise G, was ebenfalls Promise B rejected. Weil C an B gekoppelt ist, rejected nun auch Promise C und catch ruft seinen Callback auf, in dem das Error-Objekt ankommt.
Kompliziert? Yup!
Rolf