Invoke fs.ReadFile(...)

  • Hallo Zusammen,


    Ich möchte eine Json File einlesen. Dafür habe ich folgende Klasse erstellt:

    Code
    'use strict'; 
    
    const fs = require('fs').promises; 
    
    module.exports.LoadUsers = async ()=> {     
        var usersRaw = await fs.readFile('c:\\TEMP\\users.json'); 
        var users = JSON.parse(usersRaw); 
        console.log(users);//Ausgabe erfolgt wie erwartet, diese Funktion ist somit ok. 
        return users; 
    }


    In der aufrufenden Klasse verwende ich das so:

    Code
    var users = userStorage.LoadUsers(); 
    
    console.log(users);// Hier ist Users immer leer.


    Ok, users muss invoked werden aber genau da hapert es bei mir. Zu dem Thema habe ich folgendes gefunden: https://stackoverflow.com/ques…get-data-from-fs-readfile


    Leider schaffe ich es nicht die beiden Funktionen auf mein Beispiel anzuwenden:

    Code
    function doSomething (callback) {
        // any async callback invokes callback with response
    }
    
    doSomething (function doSomethingAfter(err, result) {
        // process the async result
    });


    Könnte mir bitte jemand zeigen wie das angewendet werden muss und auch erklären was da passiert? Ich verstehe nicht, wie mit den beiden Funktionen ein Invoke zustande kommt.


    Vielen Dank schon mal! 😊


    Herzliche Grüße

    Christoph

  • Hi Christoph1972


    Schau' dir mal das an:

    Making asynchronous programming easier with async and await (mdn)

    Callbacks, Promises, and Async (scotch.io)


    Die Methode (LoadUsers) die dein Modul zur Verfügung stellt, ist mit async gekennzeichnet.

    Das bedeutet, das der Rückgabewert auf jeden Fall ein Promise ist.

    Zitat

    console.log(users);// Hier ist Users immer leer.

    Die Variable users ist hier warscheinlich nicht wirklich "leer" sondern enthält ein Promise, das du ganz einfach auflösen kannst.

    Entweder mit einem .then()oder mit einem vorangestellten await (in einem async Kontext)


    Das Beispiel, dass du zum Schluss gepostet hast, ist eine Variante, die mit "callbacks" arbeitet. (Siehe die Links)

    Das hilft dir hier aber auch nicht weiter, denn dein Modul benutzt die Promise API und keine "callbacks"


    Grüße

    Andreas

  • Hallo Andreas,


    vielen Dank für die beiden Links! Ich werde das heute Abend im Bett lesen. Scheinbar habe ich die Themen noch nicht richtig verstanden. Ich drehe mich immer im Kreis. Auf deinen Hinweis mit dem Promise habe ich die Funktion noch mal überarbeitet, leider erfolglos.


    So sieht jetzt das Modul LoadUsers aus:


    Und so in der aufrufenden Klasse:

    Code
    var _users = [];
    
    userStorage.LoadUsers((users) => {
         console.log(users);//User
         _users = users;
    });
    
    console.log(_users);//Keine User



    Wie bekomme ich die User in den Kontext der aufrufenden Klasse?


    Vielen Dank schon mal!


    Herzliche Grüße

    Christoph

  • Hallo Christoph,


    Zitat

    Wie bekomme ich die User in den Kontext der aufrufenden Klasse?

    Kurze Antwort: Niemals!


    Erklärung:

    was du hier erlebst, ist die größte Herausforderung bei der Asynchronen Programmierung: Die Asynchronität.


    Wenn man sich die Reihenfolge anschaut, in der die Funktionen aufgerufen werden, sieht man auch warum:


    Zusammengefasst, existieren die Daten nur im Scope (Kontexts) des onLoadUsers Callbacks.

    Wenn du also mit den Daten weiterarbeiten möchtest, musst du das in diesem Scope tun.


    Ich hoffe ich konnte ein wenig Klarheit in dieses Thema bringen, es ist mit das schwerste, was in der Programmierung existiert.



    Grüße

    Andreas

  • Zitat von AndreasB

    es ist mit das schwerste, was in der Programmierung existiert.

    Dann brauche ich mir ja keine Vorwürfe zu machen, dass ich diese Sache mit async und await noch nicht richtig verstanden habe :D


    Der Link auf MDN scheint sehr gut zu sein. Ich habe ihn noch nicht genau durch gelesen aber beim Überfliegen ist mir gleich aufgefallen: Sie schreiben:

    Zitat von MDN

    Async/await makes your code look synchronous, and in a way it makes it behave more synchronously. The await keyword blocks execution of all the code that follows until the promise fulfills, exactly as it would with a synchronous operation. It does allow other tasks to continue to run in the meantime, but your own code is blocked.

    Da sehe ich einen Widerspruch: Auf der einen Seite wird dringend empfohlen, bei XMLHttpRequest oder dem Ajax von jQuery nicht auf synchron zu schalten, weil der Browser dann während des Wartens auf die Antwort blockiert ist. Und auf der anderen Seite jetzt auf einmal async und await, wo das genau so der Fall ist?

  • Hallo Sempervivum,


    du hast recht, das scheint auf den ersten Blick widersprüchlich zu sein, ist es aber nicht.

    Der Begriff, "synchron" ist sehr dehnbar ;)


    Der Grund, weshalb es empfohlen wird, bei XMLHttpRequest.open() den asynchronous Flag zu setzen ist der, dass ohne diesen auch die Ausführung aller anderen Tasks den Browsers pausiert wird.


    Synchronous XHR requests often cause hangs on the web.


    Dies ist bei der Verwendung des await Keywords nicht so:

    Zitat von mdn


    "It does allow other tasks to continue to run in the meantime, but your own code is blocked."

    Wie der Browser das bewerkstelligt, kann ich dir aber leider nicht sagen.



    Grüße

    Andreas

  • AndreasB

    Vielen Dank für die ausführliche Erläuterung, wirklich sehr nett, dafür müsste ich eigentlich ein Bier ausgeben! :)


    Kurze Antwort: Niemals!

    Genau das war die Info die brauchte. Eigentlich hatte ich vor die "_users" bei der Initialisierung zu laden. Jetzt werde ich sie immer laden wenn ich auf sie zugreife, dann kann ich auch sicher sein das die Liste aktuell ist.


    Wir halten fest: async/await hat den Zweck das UI nicht einfrieren zu lassen und den Code leserlicher zu halten. 8)


    Herzliche Grüße
    Christoph

  • Hallo Christoph,


    Außerdem ist es für das Verständnis von async await wichtig zu wissen, dass sie auf Promise basieren.

    Eigentlich hatte ich vor die "_users" bei der Initialisierung zu laden

    Das kannst du immer noch so machen.

    Du kannst halt dein Programm erst starten, wenn alle Daten da sind. So wie du das Beispielsweise im Web machst, wenn du darauf wartest, dass der DOM vollständig geladen ist.


    In etwa so:

    JavaScript
    function main (users) {
        // Hier sind die User geladen
    }
    
    function err (reason) {
       // Hier landen wir wenn beim Laden ein Fehler auftrat.
    }
    
    loadUser().then(main, err);

    Es kommt natürlich immer darauf an, was du machen willst.


    Grüße

    Andreas

  • Hallo Andreas,

    Das kannst du immer noch so machen.

    Du kannst halt dein Programm erst starten, wenn alle Daten da sind. So wie du das Beispielsweise im Web machst, wenn du darauf wartest, dass der DOM vollständig geladen ist.


    Das verstehe ich jetzt nicht. Dann habe ich doch wieder das problem mit dem Kontext??

    Code
    var _users = [];
    
    function main (users) {
        _users = users; 
    }


    Würde das in dem Fall funktionieren?


    Herzliche Grüße
    Christoph

  • Hallo Christoph,


    Würde das in dem Fall funktionieren?

    wenn du in dem Kontext der main Funktion bis zum Ende bleibst ja. Dann ist das ja so, als wenn du die variable erst in der main deklariert hättest:

    JavaScript
    function main (users) {
        var _users = [];
        _users = users; 
    }



    Ich hatte deine erste Frage so verstanden, als wenn du auf die geladenen User im übergeordneten Kontext zugreifen möchtest und das ist aus timing Gründen nicht möglich.



    Grüße

    Andreas

  • AndreasB Sorry für die späte Antwort, ich hatte nur sehr wenig Zeit!


    wenn du in dem Kontext der main Funktion bis zum Ende bleibst ja. Dann ist das ja so, als wenn du die variable erst in der main deklariert hättest:


    Könnte ich den gesamten Code in der Main Funktion lassen? Das stelle ich mir aber irgend wie wenig elegant und unübersichtlich vor.


    Vielen Dank für die Unterstützung!


    Herzliche Grüße
    Christoph

  • Christoph1972 Du kannst den kompletten Code in die main schreiben.

    Denk immer daran, dass du auch Funktionen in anderen Funktionen deklarieren und aufrufen kannst.

    Außerdem kannst du natürlich auch modul-Funk tionen in einer Funktion aufrufen.


    Solange du darauf achtest, dass die main dein Einstiegspunkt für dein Programm ist, ist alles Ok.



    Grüße

    Andreas


Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!