Rolf B: Frage zu fetch und Übergabe von Array, Aufruf aus anderer .js

Beitrag lesen

Hallo JustMe28,

fetch ist asynchron. Es kehrt sofort zurück. Die Daten stehen erst zur Verfügung, wenn der then-Handler aufgerufen wird.

Deine showArray-Funktion kann deshalb eigentlich nicht funktionieren, es sei denn, die Arraydarstellung, die der Browser in die Konsole schreibt, wird in der Konsole bei nachträglichen Änderungen aktualisiert. Keine Ahnung, käme mir komisch vor.

Korrekt wäre es, das fetch-Promise aus der fillArray Funktion zurückzugeben und darauf einen neuen then-Handler zu setzen, so dass das asynchrone Konzept durchgehalten wird. Das kann man unter einem Haufen Syntaxzucker verschütten, mit dem async-await Muster, aber ich weiß nicht, ob ich Dir das zumuten kann.

function fillArray(url) {
   return fetch(url)
          .then(response => response.json())
          .then(data => {
             let array = [];
             // Array aus data-response aufbauen
             // UND ZURÜCKGEBEN. KEINE GLOBALE VARIABLE VERWENDEN!
             return array;   
          });
}

Um diesen Code wirklich zu verstehen, muss man Promises durchschauen. Die fetch-Funktion schickt den HTTP Request an die genannte URL und kehrt dann mit einem Promise A zurück. Auf diesem Promise wird die erste then-Methode aufgerufen, um eine Funktion zu registrieren, die das Ergebnis des fetch-Aufrufs verarbeiten soll. Das ist dieses response => response.json(). Es ist eine Pfeilfunktion, die nichts weiter tut, als auf dem response-Objekt die json-Methode aufzurufen und das Ergebnis der json-Methode zurückzugeben.

Aus then kommt ein neues Promise B zurück. Im einfachsten Fall erfüllt sich B, wenn A erfüllt ist und die mit dem ersten then registrierte Funktion einen einfachen Wert zurückgibt. Das ist hier aber nicht der Fall, denn response.json() gibt seinerseits ein Promise C zurück. Das geschieht, weil der Datenstrom vom Server in dem Moment, wo der erste then-Handler läuft, noch gar nicht fertig gelesen ist. Das passiert erst innerhalb von json().

Der Umstand, dass die Funktion im ersten then das Promise C zurückgibt, führt dazu, dass JavaScript Promise B mit Promise C verknüpft. Sobald C sind erfüllt und einen Wert bereitstellt, erfüllt sich auch B.

Darauf wird mit dem zweiten then reagiert. Hier wird eine Funktion hinterlegt, in der die von json() ermittelten Daten verarbeitet werden. Dieses zweite then gibt wiederum ein Promise D zurück, das sich nach den gleichen Regeln erfüllt wie Promise B.

Beachte das return vor dem fetch. Es gibt den Wert zurück, der sich aus dem vollständigen Ausdruck dahinter ergibt, also fetch(...).then(...).then(...). Der Wert dieses Ausdrucks ist das Promise, das vom zweiten then geliefert wird, also das Promise D. Das geht an den Aufrufer von fillArray zurück, und der kann nun damit wieder weiterarbeiten.

function showArray() {
   fillArray(url)
   .then(array => {
      // Jetzt steht das Array sicher zur Verfügung und 
      // kann verarbeitet werden
   });
}

Wenn Du meinst, dass Du es unbedingt musst, kannst Du an dieser Stelle das array-Argument in der globalen Variablen speichern.

Noch kurz zu async-await. Das ist ein Syntaxzucker um Promises herum, und man könnte fillArray und showArray damit auf diese Weise aufbauen:

async function getArray(url) {
   let response = await fetch(url);
   let jsonData = await response.json();
   let array = [];
   // Array aus jsonData füllen
   return array;
}

function showArray(url) {
   getArray(url)
   .then(array => {
      // verarbeiten
   });
}
// ODER
async function showArray(url) {
   array = await getArray(url);
   // array verarbeiten
}

await ist nur in async-Funktionen zulässig. Wesentliche Eigenschaft von async-Funktionen ist, dass sie ihr Ergebnis grundsätzlich als Promise zurückliefern und nicht in dem Moment ausgeführt werden, wo man sie aufruft, sondern in die Mikrotask-Queue eingestellt werden. Was in der Mikrotask-Queue steht, wird erst dann ausgeführt, wenn der eigentliche JavaScript-Aufruf fertig ist und der Browser bereit für eine Anzeigeaktualisierung wäre.

Deswegen muss man genau überlegen, ob es sinnvoll ist, eine Funktion async zu machen oder nicht. Vor allem, wenn man mit globalen Variablen hantiert, führt das zumeist zum Chaos, weil die Funktion nicht dann läuft, wenn man sie aufruft, sondern erst als Mikrotask. Aber das ist bei allem, was mit Promises zu tun hat, so.

Rolf

--
sumpsi - posui - obstruxi