ebody: Funktion mit fetch() soll kein Promise, sondern Daten liefern

Hi,

kann man es vermeiden then und catch bei dem Aufruf der Funktion verwenden zu müssen? Die Funktion selbst wartet ja schon auf das Ergebnis. Wenn man in der Funktion und im Funktionsaufruf then und catch verwenden muss, erscheint es mir unnötig doppelt verwendet zu werden und falsch.

/* Variante 1 */ 
async function load_1(apiURL){
  try{
    // Ausführen der HTTP-Anfrage, um JSON-Daten abzurufen
    const response = await fetch(apiURL);

    
    // JSON-Response speichern
    const json = await response.json();
    
    // Daten zurückgeben
    return await json.data;
  
  } catch(err){
    // Fehlerbehandlung
    throw err;
  }
}

const data1a = load_1('https://reqres.in/api/users/');
console.log('data1a',data1a); // => Promise

Wenn man load_1() aufruft, soll die Funktion direkt die Daten und kein Promise liefern. Wie kann man das machen?

Gruß ebody

  1. Hallo ebody,

    Wenn man load_1() aufruft, soll die Funktion direkt die Daten und kein Promise liefern. Wie kann man das machen?

    Gar nicht. Fetch ist asynchron, das wirst Du nicht los.

    const json = await response.json();
    // Daten zurückgeben
    return await json.data;
    

    Öhm, der await für json.data ist unnötig. response.json() interpretiert das Request-Ergebnis als JSON-String und macht ein Objekt daraus. Damit ist die Asynchronität am Ende.

    Für das Promise bleibt Dir nur

    const data1a = await load_1('https://reqres.in/api/users/');
    console.log('data1a',data1a); // => Promise

    Wenn dieser Code auf dem Top-Level läuft, haut JS ihn Dir um die Ohren. Top-Level await ist nur in ECMAScript-Modulen zulässig. Das hat Konsequenzen:

    • Der strikte Modus wird aktiviert
    • Wenn das Script extern ist, wird es mit defer geladen (d.h. asynchron geladen und direkt vor dem Triggern des DOMContentLoaded-Events ausgeführt)
    • Top-Level Variablen sind nicht mehr global, sondern nur im Modul global.

    Wenn das für deinen Code passt (oder dein Code passend gemacht werden kann), dann füge deinem Script-Statement ein type="module" hinzu und der Top-Level await ist möglich.

    Alternative B ist das Einkapseln des ganzen Steuerung in eine weitere async-Funktion. Da geht immer ein await.

    Alternative C ist

    load_1('https://reqres.in/api/users/')
    .then(data1a => console.log('data1a',data1a));
    
    console.log("Huhu, hier bin ich!");
    

    Wichtig ist bei .then, dass der Code im then erst läuft, wenn Fetch fertig ist. Der Huhu-Log wird hingegen ausgegeben, während der Fetch noch busy ist.

    await ist Syntaxzucker, der einfach den ganzen Rest einer Funktion in einen then-Callback umwandelt.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hi Rolf,

      vielen Dank. Ganz ehrlich verstehe ich das Prinzip nicht, also kann es nicht nachvollziehen (bezieht sich nicht auf deine Antwort). Es muss doch möglich sein, eine Funktion zu erstellen, mit der ich Daten abfrage. Diese Funktion wartet so lange bis die Daten geladen sind und gibt die Daten zurück. Ich dachte, dafür wären fetch und await gedacht.

      Ruft man load_1('https://reqres.in/api/users/') auf, erhält man also direkt die Daten.

      Hintergrund ist, dass ich eine Klasse erstellen möchte, die eine Methode enthält, um Daten zu laden. Erstellt man eine Instanz und ruft die Methode auf fände ich es viel schöner, wenn man einfach const data = Data.load(url); aufrufen muss, anstatt const data = Data.load(url).then...;

      Wäre dann Ajax oder ein anderer Weg in dem Fall die bessere Alternative?

      Gruß ebody

      1. Hallo ebody,

        sowohl fetch wie auch XMLHttpRequest (Ajax) arbeiten asynchron. JavaScript im Browser macht keine synchrone I/O, das kann nur node.js.

        Es war einmal anders. Die open-Methode von XMLHttpRequest kennt einen async-Parameter, dem Du false übergeben kannst. Dann läuft der Request synchron ab.

        Synchrone HTTP Requests im Hauptthread sind missbilligt. Die Browserhersteller sind dabei, dieses Szenario als Fehler zu definieren. NICHT MACHEN!!!

        Wenn Du einen WebWorker erstellst, sind synchrone Requests zulässig. Aber ein WebWorker läuft selbst asynchron zum Hauptthread.

        Es muss doch möglich sein, eine Funktion zu erstellen, mit der ich Daten abfrage. Diese Funktion wartet so lange bis die Daten geladen sind und gibt die Daten zurück.

        In WebWorkern und in Batch-Tools, die mit Node.js laufen - ja.

        In einem ereignisorientierten Umfeld - nein. Das trifft für Browser zu und für Serverdienste mit node.js. Dort ist JavaScript ein Tool zur Ereignisverarbeitung und jeder JavaScript-Aufruf muss schnell fertig werden, denn so lange ein Event verarbeitet wird, müssen alle übrigen warten. Ein Browser oder Server würden dadurch blockiert werden.

        Das ist das Grundprinzip aller graphischen UIs - der User macht was und daraus resultieren Ereignisse. Diese werden ans Anwenderprogramm geschickt und eins nach dem anderen verarbeitet. Ein paar Ereignisse können in eine Queue gestellt werden, aber nur eine Handvoll, denn andernfalls würde eine langsame Verarbeitung dazu führen, dass der User nichts mehr tut, aber das Programm noch sekundenlang den Ereignissen hinterher hechelt. Deswegen blockiert das UI, wenn die Eventqueue voll ist.

        Rolf

        --
        sumpsi - posui - obstruxi