Node Js asynchrone Router

BTCStorage

Ensign
Registriert
Mai 2020
Beiträge
140
Hallo, ich habe eine einfache Frage, ich habe ein Node js Router und ich will das er direkt eine Antwort sendet damit es keine Timeout Fehler gibt, ich habe den Code der etwas Zeitintensiver ist in eine Promise gestellt und dadrunter den Befehl der eine Antwort sendet, ich bin mir nicht ganz sicher ob der Router jetzt jedesmal erst auf die Promise warten wird oder die Antwrt direkt sendet, ich habe zumindest keine await benutzt fuer die Promise, aber bin mir nicht ganz sicher wie Node js das bearbeitet.

Das Objekt was gesendet wird ist global und deswegen kann es eigentlich jedesmal direkt gesendet werden und bei Aufruf des Routers wird dann noch im Hintergrund die Promise jedesmal neu gestartet und so das objekt geupdated, das ist meine eigentliche Idee, kann mir jemand sagen ob ich das so gut aufgebaut habe, hier mein Code:

Javascript:
let objektKunden=[];
app.get('/getuser', async function (req, res)
{
  try
  {
     new Promise((resolve) => {
      //console.log(getuser);
      
      // Filtere Datensätze
      const kundenData = [];
      const masterData = [];

        Kunden.forEach(item => {
          if (item.note !== "master") {
            kundenData.push(item);
          } else {
            masterData.push(item);
          }
        });
      objektKunden[0]=kundenData;
      objektKunden[1]=APIKeyInvalid;
      objektKunden[2]=Masteraccounts;
      objektKunden[3]=masterData;
      const responseJSON = JSON.stringify(objektKunden);     
  });
  res.status(200).json(objektKunden);
  }
  catch (error)
  {
    console.error("Fehler in getuser:", error);
    res.status(500).send("Interner Serverfehler");
  }
});
 
Folgende Dinge sind mir aufgefallen:
  • Javascript:
    Kunden
    wird nirgendwo gesetzt
  • Javascript:
    responseJSON
    wird nirgendwo verwendet
  • ich sehe in deinem gesamten Code keinen Aufruf einer asynchronen Funktion

Ich vermute hier ein XY-Problem - was genau hast du vor? Was meinst du mit
ich will das er direkt eine Antwort sendet damit es keine Timeout Fehler gibt
 
Hallo,

ich will das der Router "getuser" das globale Objekt "objektKunden" immer direkt sendet damit es keine Timeout Fehlermeldungen gibt, aber zur zeit sehe ich das es manchmal vorkommt, ich weis nicht ob es nur an diesen Router liegt oder wahrscheinlich sind meine anderen Router auch nicht so optimal asynchron aufgebaut.

Was ich also erreichen will ist das im Hintergrund das globale Objekt "objektKunden" immer wieder neu geupdated wird, dies soll aber asynchron passieren und der ROuter "getuser" soll nicht jedesmal erst warten bis die Promise durchgelaufen ist.

xeon.inc schrieb:
Folgende Dinge sind mir aufgefallen:
  • Javascript:
    Kunden
    wird nirgendwo gesetzt
  • Javascript:
    responseJSON
    wird nirgendwo verwendet
  • ich sehe in deinem gesamten Code keinen Aufruf einer asynchronen Funktion

Ich vermute hier ein XY-Problem - was genau hast du vor? Was meinst du mit

Das Objekt "Kunden" ist auch global in der Serverdatei und die Promise im Router "getuser" nutzt die Daten aus dem Objekt und erstellt dann damit das Objekt "objektKunden" welches der Router jedesmal als Antwort senden soll.

Wie mueste ich diesen "getuser" Router den am besten aufbauen damit es so wie gewuenscht ablaeuft, es soll also immer direkt das Objekt "objektKunden" als Antwort gesendet werden ohne auf den Ablauf der Promise zu warten.

Die Promise Aufgabe welche im ich im Router "getuser" habe soll eigentlich nur dafuer sorgen das dieses Objekt immer wieder von Zeit zu Zeit geupdated wird, ich wollte dafuer keine Interval Funktion bauen, weil es eigentlich nicht noetig ist, es sei den das was ich vorhabe ist nichts anders zu loesen. Vielleicht habe ich ja irgendetwas mit dem ganzen Javascript Asynchron nicht verstanden. Ich dachte mir wenn ich den Code in eine Proise einbaue wird es asynchron im Hintergrund abgearbeitet ohne das der Router auf die Erfuellung der Promise wartet Ich will ja erreichen das der Router immer schnell eine Antwort gibt deswegen habe ich gedacht dieser Aufbau koennte so funktionieren.
 
Wenn ich den ganzen router in so eine async () => funktion einbaue dann mueste der router auch immer asynchron ablaufen oder?

Beispiel:

Javascript:
let objektKunden=[];
app.get('/getuser', async function (req, res)
{
  (async () =>
  {
  try
  {
    console.log("getuser " + Date.now());
 
    // Sofortige Antwort an den Client
    res.status(200).json(objektKunden);

    // Promise für asynchrone Hintergrundoperation
    new Promise((resolve, reject) => {
    try {
         
          // Filtere Datensätze mit exchange: 1 heraus
          const newData = [];
          const masterData = [];

            Kunden.forEach(item => {
              if (item.note !== "master") {
                newData.push(item);
              } else {
                masterData.push(item);
              }
            });

          objektKunden[0]=newData;
          objektKunden[1]=APIKeyInvalid;
          objektKunden[2]=Masteraccounts;
          objektKunden[3]=masterData;
          const responseJSON = JSON.stringify(objektKunden);

         console.log("getuser Promise loop end "+Date.now());
         resolve(1);
     }
     catch (error)
     {
        reject(error); // Fehler im Promise behandeln
     }
   
  })
  .then((result) => {
    console.log("getuser promise abgeschlossen mit Ergebnis: " + result + " " + Date.now());
  })
  .catch((error) => {
    console.error("Fehler in getuser promise:", error);
  });
 
  }//try
  catch (err)
  {
     console.log("getuser asynchron catch err "+err);    
     res.status(200).json(0);
  }
  })();

});

Der Router antwortet irgendwie schon etwas schneller seitdem ich das Senden der Antwort direkt am Anfang geschrieben habe, davor stand der Befehl fuer Antwort senden erst nach der Promise, aber ich will gerne diese asynchrone Sachen noch etwas mehr lernen
 
Ich glaube, du verwechselst Promises mit Threads. Die Verwendung eines Promise führt nicht dazu, dass der Code im Hintergrund abläuft oder ähnliches.

Du kannst also in deinem Code das "new Promise" wegnehmen und das Verhalten sollte sich nicht verändern.

Wie lange braucht denn der Code mit dem "Kunden.forEach"? Bist du sicher, dass das überhaupt ein Performance-Problem ist? Der Code ist so simpel, dass das eigentlich erst bei mehreren Millionen Kunden zu einem Problem werden sollte.
 
  • Gefällt mir
Reaktionen: BTCStorage
Soweit ich das verstanden habe laeuft ja alles in einem Thread ab und man sollte nicht blockierenden asynchronen Code schreiben.

Damit eine Funktion asynchron ablaeuft sollte man das Stichwort "async" einer Funktion hinzufuegen.

Aber ich bin mir nicht sicher ob meine Funktionen dann auch alle asynchron ablaufen nur weil ich das Stichwort "async" hinzufuege.

Ich will erreichen das das Kunden Objekt asynchron im Hintergrund bearbeitet wird und der Router immer direkt das Objekt sendet.

Ich habe mir jetzt angewoehnt diese Schreibeweise zu benutzen:

Javascript:
(async () =>
{
try
{
      Programmcode
}
catch(err)
{
   console.error("Fehler :", error);
};
})();

So denke ich wird der Code immer asynchron ausgefuehrt

Ich weis nicht genau wie lange es dauert bis das Kunden Objekt bearbeitet und gesendet wird, aber seitdem ich es ganz am Anfang geschrieben habe im Router funktioniert alles schneller, das Kundenobjekt kann schon gros werden, wenn man beispielweise nur drei Kontos drine gespeichert hat und ein Konto hat tausende geschlossene Trades welche auch alle im Objekt stehen dann dauert es schon sichtbar laenger das Objekt zu senden, ich habe da deswegen auch schon einige Aenderungen gemacht und nicht alle geschlossenen Trades direkt im Objekt gespeichert sondern nur die noetigsten Daten.
 
BTCStorage schrieb:
Damit eine Funktion asynchron ablaeuft sollte man das Stichwort "async" einer Funktion hinzufuegen.
Das stimmt nur bedingt. Wenn du eine IO-Funktion, wie "readFile()" oder "fetch()" aufrufst, dann läuft diese in der Tat asynchron im Hintergrund ab.

Aber das, was du machen willst, ist ja eine CPU-lastige Berechnung. Und das blockiert dann zwangsläufig den Main-Thread von NodeJS.

Ein Workaround wäre, dass du deine Berechnung regelmäßig unterbrichst, sodass der Main-Thread dann andere Dinge abarbeiten kann.

BTCStorage schrieb:
Ich weis nicht genau wie lange es dauert bis das Kunden Objekt bearbeitet und gesendet wird, aber seitdem ich es ganz am Anfang geschrieben habe im Router funktioniert alles schneller,
Dein jetziger Code reagiert schnell, weil du das "res.status(200).json()" VOR der Berechnung machst. Er antwortet also erst dem Client und macht erst danach die aufwendige Berechnung.

Ich würde dir aber zuerst einmal empfehlen, wirklich genau zu messen, wie lange die Berechnung dauert. Ansonsten optimierst du hier ins Blaue hinein.
 
Je groeser das Kundenobjekt wird desto langer wird auch alles dauern, das ist zummindest immer so, ich frage mich zur Zeit was fuer Moeglichkeiten hat man den solche Sachen schonend auf zu bauen. Du sagst wenn man die Berechnungen regelmaessigg unterbricht koennte es etwas nutzen, meinst du damit zb wenn man sowas wie eine Flag benutzt und dann nur jede Minute mal diese foreach Schleife anwendet anstatt bei jeden Aufruf des Routers?

Und ich hoffe doch das ich auch wenigstens jetzt alles so aufgebaut habe das es wirklich asynchron und nicht blockierend ablaeuft, das mueste ja normal so sein wenn man den Code in diese Klammer "async () =>" einbaut oder?
 
Angenommen du hast eine Funktion, die sehr lange braucht:
Javascript:
function longComputation() {
    for(let i=0;i<1000000;i++) {
        doStuff();
    }
}

Dann ist es vollkommen egal, ob du das irgendwie in async verpackst. Es wird immer den Main-Thread blockieren, weil NodeJS es in einem Durchlauf komplett ausführt.

Was du machen kannst, ist Folgendes:
Javascript:
async function longComputation() {
    for(let i=0;i<1000000;i++) {
        if(i % 10000 == 0) {
            await new Promise(resolve => setTimeout(resolve, 1));
        }
        doStuff();
    }
}

Hier wird alle 10000 Durchläufe kurz gewartet (durch das setTimeout), sodass der Main-Thread sich um andere Aufgaben kümmern kann.

Eine andere Option wäre, Worker Threads von NodeJS zu benutzen. Dann hast du richtiges Multi-Threading, aber es ist auch komplizierter.
 
Zurück
Oben