Forum: PC-Programmierung Javascript Node. Wie bekomme ich hier einen return hin


von Martin M. (ats3788)


Lesenswert?

Hallo
ich spiele ein wenig mit JavaScript Node herum leider
bekomme ich nur ein undentified zurück, warum das so ist habe ich schon 
herausgefunden.

1
 
2
3
module.exports = {
4
5
    query_database : function(query, SQL_ID,       )
6
{
7
8
  
9
    //"select distinct * from main"
10
    connection.query(query, function(err, recordsArray, fields) {
11
          if (err) {
12
            console.log("Error occured while fetching the data - module database !!")
13
        } else {
14
          
15
           var jsonStr = JSON.stringify(recordsArray); // Important Make a Sting fom an Object we get 
16
            
17
          const objJson = JSON.parse(jsonStr);
18
 
19
           const myfunction = require("../myfunctions/myfunctions");   
20
           const  obj = myfunction.fetch_Json(objJson, SQL_ID); // Here I get a specific Dataset
21
            console.log(obj); // Here I het my Json Object
22
23
            return(obj); //return is undentified because a function in a function
24
       
25
          }
26
        
27
       })
28
       
29
      }
30
  }

eine function in einer function

bei einer einfachen function kein Problem

https://stackoverflow.com/questions/52346981/create-callback-in-node-js-module-exports
Ich müßte der funktion query_database den Wert übergeben , nur wie ist 
die Frage

von Εrnst B. (ernst)


Lesenswert?

Dein Problem ist weniger die function in der function, dein Problem ist 
die Asynchrone Arbeitsweise deines "DB"-Moduls.

Aus der Äusseren Funktion bist du schon rausgelaufen, bevor die innere 
überhaupt angefangen hat. d.H. mit "return" kommst du nicht weiter.

Deine query_database function muss entweder asynchron werden, dann kann 
sie vor ihrem return auf die datenbank-query warten, oder muss eine 
callback-funktion als parameter bekommen, die erst aus der inneren 
Funktion heraus aufgerufen wird.

von 🐧 DPA 🐧 (Gast)


Lesenswert?

Dein Problem ist nicht, dass eine Funktion in einer anderen Funktion 
ist, sondern dass die zweite Funktion asynchron (also später) aufgerufen 
wird.
Die erste Funktion ist zu dem Zeitpunkt, wo die andere aufgerufen wird, 
schon längst wieder beendet. Ein äquivalentes Szenario zum 
veranschaulichen hier:
https://jsfiddle.net/5c7ue1vg/2/
1
function x(){
2
  console.log("function x called");
3
  console.log("Asynchronousely calling y");
4
  setTimeout(function y(){
5
    console.log("function y called");
6
  },0);
7
  console.log("returning from x");
8
}
9
console.log("Calling x");
10
x();


Bei einer Funktion, die längst zurückgekehrt/durchgelaufen/beendet ist, 
kann man natürlich nichts mehr zurück geben. Aber die 2te Funktion, kann 
eine Funktion aufrufen, die der ersten übergeben wurde. Eine solche 
Funktion nennt man deshalb callback funktion (Rückruffunktion).
1
function x(callback){
2
  console.log("function x called");
3
  console.log("Asynchronousely calling y");
4
  setTimeout(function y(){
5
    console.log("function y called");
6
    console.log("Calling callback function");
7
    callback(null, "something something");
8
  },0);
9
  console.log("returning from x");
10
}
11
console.log("Calling x");
12
x(function z(err, result){
13
  console.log("Function z here, I got called! I got:", result);
14
});

Das pattern, bei Callbacks fehler, dann resultat als Argument 
mitzugeben, und den Letzten Parameter ein Callback zu machen, ist nur 
eine Konvention, die sich früher mal durchgesetzt hat. Es hat den 
Vorteil, dass man nicht ständig bei jeder Funktion nachsehen muss, wie 
man den callback übergeben muss, wie man Fehler erkennt, etc. Es ist 
aber nicht zwingend.

Das Problem daran ist halt, dass man die Funktionen auseinandernehmen 
und / oder verschachteln muss, Dinge in callbacks verschieben halt...

Eine erste Verbesserung gab es dann mit Promises.
1
function x(){
2
  console.log("function x called");
3
  let result = new Promise(function q(resolve, reject){
4
    console.log("Asynchronousely calling y");
5
    setTimeout(function y(){
6
      console.log("function y called");
7
      console.log("Calling callback function");
8
      resolve("something something");
9
    },0);
10
  });
11
  console.log("returning from x");
12
  return result;
13
}
14
console.log("Calling x");
15
let result = x();
16
console.log("Lets let it call a callback once we actually have a result (the promise is fulfilled)");
17
result.then(function z(result){
18
  console.log("Function z here, I got called! I got:", result);
19
});
20
console.log("Keep in mind, here it wasn't called yet!");

Ein Promise (=Versprechen) Objekt verlagert, woher das Callback kommt. 
Man muss es der Funktion nicht mehr direkt mit geben. Statdessen ist das 
Promise Objekt stellvertretend für ein zukünftiges Resultat, oder einen 
zukünftigen Fehlschlag da. Da das Promise Objekt in der ersten Funktion 
erstellt wurde, kann es von dieser zurückgegeben werden. Und mit .then 
und einer callback funktion kann man dann auf ein Ergebnis, oder einen 
fehler warten. Wobei es für letzteres noch die .catch Methode gibt.

Jede Funktion die die callback Konvention nutzt kann man so in ein 
Equivalent mit promises überführen. Ein Vorteil der Promises ist noch, 
dass beim callback der .then Methode, diese ein Resultat und sogar 
wieder eine Promise zurückliefern kann, und die .then Methode selbst 
auch eine Promise zurück liefert, die dann stellvertretend für dieses 
neue Resultat steht. Damit kann man aus einer Verschachtelung eine Kette 
machen.

Also z.B. aus dem hier: (callback style)
1
function c_hallo(callback){
2
  callback(null, "Hallo")
3
}
4
5
function c_martin(str, callback){
6
  callback(null, str + " Martin");
7
}
8
9
function c_uppercase(str, callback){
10
  callback(null, str.toUpperCase());
11
}
12
13
c_hallo(function(err, result){
14
  c_martin(result, function(err, result){
15
    c_uppercase(result, function(err, result){
16
      console.log(result);
17
    })
18
  });
19
});

Kann man das hier machen: (promise style)
1
function p_hallo(callback){
2
  return new Promise(function(resolve){
3
    resolve("Hallo");
4
  });
5
}
6
7
function p_martin(res){
8
  return new Promise(function(resolve){
9
    resolve(res + " Martin");
10
  });
11
}
12
13
function p_uppercase(res){
14
  return new Promise(function(resolve){
15
    resolve(res.toUpperCase());
16
  });
17
}
18
19
p_hallo()
20
  .then(p_martin)
21
  .then(p_uppercase)
22
  .then(console.log);

Btw. in diesem speziellen fall könnte man das auch kürzer schreiben:
1
Promise.resolve("Hallo")
2
  .then(res => res + " Martin")
3
  .then(res => res.toUpperCase())
4
  .then(console.log);

Weil eigentlich alle diese 2 Konventionen so konsequent durchziehen, 
gibt es in node convinience Funktionen, um bestehende Funktionen in die 
ander Variante zu überführen, nähmlich die Funktionen util.promisify und 
util.callbackify. util.promisify(c_hallo) liefert eine Funktion zurück, 
die equivalent zu p_hallo. Und util.callbackify(p_hallo) liefert eine 
Funktion zurück, die equivalent zu c_hallo ist. Wenn man also eine 
Variante hat, aber die andere braucht, nimmt man einfach diese 2 
Hilfsfunktionen.

Mit ES7 und async await wurde das dann weiter vereinfacht. async await 
sind Syntax Konstrukte  um une die ganzen .then und separate Callbacks 
auszukommen. Damit sieht eine asynchrone Funktion wieder fast genau so 
aus, wie eine Synchrone.

Die p_uppercase Funktion kann mit async wie folgt geschrieben werden:
1
async function p_uppercase(res){
2
  return res.toUpperCase();
3
}

Das coole daran sieht man aber, wenn man die .then chain von oben 
schreibt:
1
async function x(){
2
  var resultat;
3
  resultat = await p_hallo();
4
  resultat = await p_martin(resultat);
5
  resultat = await p_uppercase(resultat);
6
  console.log(resultat);
7
}
8
x();

Oder auch:
1
async function x(){
2
  console.log( await p_uppercase( await p_martin( await p_hallo() ) ) );
3
}

Mit await "wartet" man quasi also auf das Resultat einer Promise, und 
wenn es ankommt, geht's weiter. Es gibt nur 2 wichtige Unterschiede die 
man bei Async funktionen beachten muss:
 1) async funktionen können überal dort, wo await steht, "unterbrochen" 
werden. Das heisst, andere async & callback functionen könnten an den 
Stellen wärend dem Warten auf das Ergebnis ausgeführt werden.
 2) Man darf nicht vergessen, das await überall hinzuschreiben, wo man 
das Resultat einer Promise braucht.

von Joachim S. (oyo)


Lesenswert?

So sollte Dein Code-Stück funktionieren:
1
module.exports = {
2
  query_database : (query, SQL_ID) => new Promise((resolve, reject) => {
3
    // "select distinct * from main"
4
    connection.query(query, (err, recordsArray, fields) => {
5
      if (err) {
6
        //console.log("Error occured while fetching the data - module database !!");
7
        reject(err);
8
      } else {
9
        const objJson = JSON.parse(JSON.stringify(recordsArray)); // Important Make a Sting fom an Object we get
10
        const myfunction = require("../myfunctions/myfunctions");
11
        const obj = myfunction.fetch_Json(objJson, SQL_ID); // Here I get a specific Dataset
12
        //console.log(obj); // Here I het my Json Object
13
        resolve(obj);
14
      }
15
    });
16
  }
17
}
Benutzen kannst Du es dann z.B. so:
1
require("<name Deines Moduls>").query_database(<query>, <SQL_ID>)
2
.then((obj) => {
3
  // Hier kommt Dein Code hin, der das obj-Objekt verwendet
4
})

oder so
1
async () => {
2
  const obj = await require("<name Deines Moduls>").query_database(<query>, <SQL_ID>);
3
  // Hier kommt Dein Code hin, der das obj-Objekt verwendet
4
}
Aber vermutlich solltest Du Dich wirklich erst einmal kurz einlesen, wie 
moderne asynchrone Programmierung in Javascript mit Promises bzw 
async/await funktioniert, sonst wirst Du vermutlich schnell auf das 
nächste Problem stossen.
EDIT: Ok, DPA hat netterweise schon mal eine Kurzzusammenfassung für 
Dich geschrieben.

: Bearbeitet durch User
von Martin M. (ats3788)


Lesenswert?

Ich danke euch das muss ich erst mal durcharbeiten.
Komme aus der Pascal Welt und dies asynchrone Verarbeitung ist sehr
merkwürdig.
Danke Joachim ja das sollte ich, nur ich wollte ein wenig mit Java 
Script herumspielen, großes habe ich nicht vor.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.