hmm: Parameter mitgeben beim Express app.get

Hi Leute,

hier mein Code:

    this.sendClient = function() {
        var app = this.createApp();
        var port = process.env.port || 8080;
        
        for(var i = 0; i < 8; i++) {
            var file = configJson.routings[i];
            if(file.sessionSite == 0) {
                app.get(file.route, function(req, res) {
                    res.sendfile(file.htmlFileName, { root: __dirname + file.pathToHtmlFile });
                });
            } else {
                app.get(file.route, function(req, res) {
                    console.log(i);
                    if(req.session.email) {
                        res.sendfile(file.htmlFileName, { root: __dirname + file.pathToHtmlFile });
                    } else {
                        var rootFile = configJson.routings[0];
                        res.sendfile(rootFile.htmlFileName, { root: __dirname + rootFile.pathToHtmlFile });
                    }
                });
            }
        }
        
        app.listen(port);
    }

das Console.log gibt mir immer 7 zurück. Der Code baut mit NodeJS/Express einfach nur Routings und hängt an jede Route eine Funktion ran die genau dann aufgerufen wird, wenn im Browser wie entsprechende Route/Url eingegeben wird.

Das i im console.log ist jetzt leider für alle Routen 7, ich möchte aber 1-7 haben. Wie kann ich das machen? Im Prinzip müsste ich irgendwo nen Parameter reinmorksen, oder?

akzeptierte Antworten

  1. Tach!

    Das i im console.log ist jetzt leider für alle Routen 7, ich möchte aber 1-7 haben. Wie kann ich das machen? Im Prinzip müsste ich irgendwo nen Parameter reinmorksen, oder?

    Du musst dir den Wert individuell im inneren Kontext der callback-Funktion merken. Wenn du von innerhalb der Funktionen auf den äußeren Kontext zugreifst, ist das i immer 7, weil die Schleife zum Zeitpunkt des Zugriffs ja bereits bei 7 angekommen ist.

    dedlfix.

    1. genau, wie mache ich das? bzw. wo finde ich eine anleitung?

      ich habe sowas versucht:

      function x() {return i;}

      app.get(route, function(req, res, x){...})

      aber da ist x() leider undefined

      1. Tach!

        genau, wie mache ich das?

        Du brauchst eine Variable, die lokal existiert und nicht global. Mit let kann man innerhalb eines Schleifenkörpers eine lokale Variable anlegen. Kopier da den jeweils aktuellen Wert von i rein. Funktionen, die in diesem Scope definiert sind, lassen auch das am Leben, was ebenfalls noch darin existiert. Also kann die Funktion auch noch auf den Schleifenkörper zugreifen und hat wegen des lokalen Scopes von let einen individuellen Zugriff unabhängig vom späteren Schleifenzustand.

        wo finde ich eine anleitung?

        Zum Beispiel im MDN, Stichwort Closures.

        dedlfix.

        1. hm, ich hab das mal so eingebaut:

              this.sendClient = function() {
                  var app = this.createApp();
                  var port = process.env.port || 8080;
                  
                  for(var i = 0; i < configJson.routings.length; i++) {
                      var file = configJson.routings[i];
                      if(file.sessionSite == 0) {
                          app.get(file.route, function(req, res) {
                              res.sendfile(file.htmlFileName, { root: __dirname + file.pathToHtmlFile });
                          });
                      } else {
                          app.get(file.route, function(req, res) {
                               "use strict";
                              let x = i;
                              console.log(x);
                              if(req.session.email) {
                                  res.sendfile(file.htmlFileName, { root: __dirname + file.pathToHtmlFile });
                              } else {
                                  var rootFile = configJson.routings[0];
                                  res.sendfile(rootFile.htmlFileName, { root: __dirname + rootFile.pathToHtmlFile });
                              }
                          });
                      }
                  }
                  
                  app.listen(port);
              }
          

          nur leider ist der log immernoch immer 7. was mache ich falsch?

          1. boar hamma! danke, funktioniert doch. hier der code:

                this.sendClient = function() {
                    "use strict";
                    var app = this.createApp();
                    var port = process.env.port || 8080;
                    
                    for(var i = 0; i < configJson.routings.length; i++) {
                        let x = i;
                        var file = configJson.routings[i];
                        if(file.sessionSite == 0) {
                            app.get(file.route, function(req, res) {
                                console.log(x);
                                res.sendfile(file.htmlFileName, { root: __dirname + file.pathToHtmlFile });
                            });
                        } else {
                             let x = i;
                            app.get(file.route, function(req, res) {
                                console.log(x);
                                if(req.session.email) {
                                    res.sendfile(file.htmlFileName, { root: __dirname + file.pathToHtmlFile });
                                } else {
                                    var rootFile = configJson.routings[0];
                                    res.sendfile(rootFile.htmlFileName, { root: __dirname + rootFile.pathToHtmlFile });
                                }
                            });
                        }
                    }
                    
                    app.listen(port);
                }
            
            1. hihihihihi, es funktioniert. hier nochmal in sinnhafter:

                  this.sendClient = function() {
                      "use strict";
                      var app = this.createApp();
                      var port = process.env.port || 8080;
                      
                      for(var i = 0; i < configJson.routings.length; i++) {
                          let file = configJson.routings[i];
                          if(file.sessionSite == 0) {
                              app.get(file.route, function(req, res) {
                                  res.sendfile(file.htmlFileName, { root: __dirname + file.pathToHtmlFile });
                              });
                          } else {
                              app.get(file.route, function(req, res) {
                                  if(req.session.email) {
                                      res.sendfile(file.htmlFileName, { root: __dirname + file.pathToHtmlFile });
                                  } else {
                                      var rootFile = configJson.routings[0];
                                      res.sendfile(rootFile.htmlFileName, { root: __dirname + rootFile.pathToHtmlFile });
                                  }
                              });
                          }
                      }
                      
                      app.listen(port);
                  }
              

              ps: ich hab soviel kaffee intus, dass ich mich gleich übergebe

          2. Tach!

            hm, ich hab das mal so eingebaut:

                    for(var i = 0; i < configJson.routings.length; i++) {
                            app.get(file.route, function(req, res) {
                                let x = i;
                            });
                    }
            

            nur leider ist der log immernoch immer 7. was mache ich falsch?

            Hab den Code mal auf das Wesentlichste gekürzt, und du hast ja schon die Lösung. Das Problem bei diesem Versuch ist, dass deine Funktion ja erst irgendwann später gecallbackt wird (wie man das so schön neudeutsch sagt - nicht). Du brauchst den aktuellen Wert von i aber zum Zeitpunkt des Schleifendurchlaufs, also muss die Ausführung der Zuweisung zu x vorher stattfinden. Der einzige Punkt ist da vor dem app.get()-Aufruf.

            dedlfix.

            1. so hab ich das gemacht:

              "user strict";
              for(var i = 0; i < configJson.routings.length; i++) {
                              let x = i;
                              app.get(file.route, function(req, res) {
                                  console.log(x);
                              });
                      }
              

              function(req, res) {console.log(x); }

              wird erst ausgeführt, wenn man die route file.route im Browser anklickt und er braucht irgendwie das use strict, sonst meckert die console.

              1. Hallo hmm,

                warum er den Strict-Mode will kann ich nicht sagen - WAS meckert die Console denn? ("user strict" war bestimmt ein Typo deinerseits)

                Dedlfixens Vorschlag von 17:46 ist übrigens nicht zielführend, weil da der let erst läuft wenn die Funktion aufgerufen wird und dann an den Wert von i nach Schleifenende gebunden wird. Da ist deine Lösung richtiger, und deine Variante mit let file=... sowieso am besten.

                Du könntest übrigens - wenn Du beim Index bleibst - auf das x verzichten, wenn Du es so machst:

                for (let i=0; i < ...; i++) {
                   // create closure with i
                }
                

                weil der let im for dafür sorgt, dass i im Kontext des Schleifen-Body liegt. Aber Achtung - laut kangax macht der IE11 das falsch.

                Rolf

                --
                Dosen sind silbern
                1. Tach!

                  Dedlfixens Vorschlag von 17:46 ist übrigens nicht zielführend,

                  Das war kein Vorschlag, das war nur die Erklärung, warum dieser seiner Versuche nicht zielführend war.

                  Da ist deine Lösung richtiger, und deine Variante mit let file=... sowieso am besten.

                  Die existierte zum Zeitpunkt meiner Antwort schon, und ich hab nur die Erklärung noch hinterhergeschoben.

                  Du könntest übrigens - wenn Du beim Index bleibst - auf das x verzichten, wenn Du es so machst:

                  for (let i=0; i < ...; i++) {
                     // create closure with i
                  }
                  

                  weil der let im for dafür sorgt, dass i im Kontext des Schleifen-Body liegt.

                  Auch nicht schlecht. Hätte ich jetzt nicht erwartet, dass i innerhalb des Schleifenbody eine unveränderliche Kopie ist.

                  Aber Achtung - laut kangax macht der IE11 das falsch.

                  Laut meinem Test auch.

                  dedlfix.

                  1. Hallo dedlfix,

                    Das war kein Vorschlag,

                    sorry, war verwirrt.

                    Rolf

                    --
                    Die Berge rufen!
                  2. Wenn man für den IE11 schreiben muss, geht es so (siehe Beispiel 4):

                    Beispiel 1 läuft nicht wie erwartet:

                    for (var x=0; x<3; x++) { 
                        setTimeout(function(){ 
                            console.log(x);   // 3,3,3
                        }, 100);
                    }
                    console.log(x);   // 3 // unsauber
                    

                    Beispiel 2: Saubere ES6 syntax, let bewirkt das erwartete Resultat und besudelt nicht den äußeren Kontext, funktioniert aber nicht im IE11:

                    for (let x=0; x<3; x++) { 
                        setTimeout(function(){ 
                            console.log(x);   // 1,2,3
                        }, 100);
                    }
                    console.log(x);   // ReferenceError: x is not defined // sauber
                    
                    

                    Beispiel 3: funktioniert auch vor ES6, die anonyme Funktion bewirkt das erwartete Resultat, aber der äußere Kontext wird besudelt.

                    for (var x=0; x<3; x++) {
                        (function(x){
                            setTimeout(function(){ 
                                console.log(x);   // 1,2,3
                            }, 100);
                        })(x);
                    }
                    console.log(x);   // 3 // unsauber
                    
                    

                    Beispiel 4: Das Wrappen in eine weitere anonyme Funktion funktioniert vor ES6 und im IE11 und der äußere Kontext bleibt sauber, aber – functionfunctionfunction:

                    (function(){
                        for (var x=0; x<3; x++) {
                            (function(x){
                                setTimeout(function(){ 
                                    console.log(x);   // 1,2,3
                                }, 100);
                            })(x);
                        }
                    })();
                    console.log(x);   // ReferenceError: x is not defined // sauber
                    
                    

                    Fazit: der einzige Grund var statt let/const zu verwenden ist wenn man für Pre-ES6 Browser schreiben muß.

                    Quellen:

                    Learning Advanced JavaScript, Beispiel 56

                    Is there any reason to use the “var” keyword in ES6?

                    Gruß, Nils