Frage

In NodeJS, gibt es praktisch keine Blockierung I / O-Operationen. Das bedeutet, dass fast alle NodeJS IO-Code viele Rückrufe beinhaltet. Dies gilt sowohl für das Lesen und Schreiben von / auf Datenbanken, Dateien, Prozesse, etc. Ein typisches Beispiel hierfür ist die folgende:

var useFile = function(filename,callback){
    posix.stat(filename).addCallback(function (stats) {
        posix.open(filename, process.O_RDONLY, 0666).addCallback(function (fd) {
            posix.read(fd, stats.size, 0).addCallback(function(contents){
                callback(contents);
            });
        });
    });
};

...

useFile("test.data",function(data){
    // use data..
});

Ich bin Antizipation Code zu schreiben, die viele IO-Operationen machen, so erwarte ich zu schreiben viele Rückrufe. Ich bin sehr zufrieden mit Rückrufen, aber ich mache mir Sorgen um all die Rekursion. Bin ich in Gefahr, in zu viel Rekursion läuft und irgendwo durch einen Stapel bläst? Wenn ich Tausende von individuellen Schreiben in meinem Schlüssel-Wert-Speicher mit Tausenden von Rückrufen zu machen, wird mein Programm schließlich abstürze?

Bin ich Missverständnis oder die Auswirkungen unterschätzt? Wenn nicht, gibt es eine Möglichkeit, um diese während zu bekommen noch NodeJS' Callback-Codierung Stil mit?

War es hilfreich?

Lösung

Keine der Code, den Sie zeigen wird Rekursion. Wenn Sie useFile nennen nennt es posix.stat(), die zurückgibt, und useFile endet, wie es vollständig ausgeführt hat. Zu einem späteren Zeitpunkt, wenn der Anruf zu posix.stat() abgeschlossen ist innerhalb des zugrunde liegenden Systems und die Ergebnisse sind verfügbar, die Callback-Funktion, die Sie für die hinzugefügt wird ausgeführt. Das ruft posix.open(), und dann endet, wie es vollständig ausgeführt hat. Sobald die Datei erfolgreich geöffnet wurde, für die Callback-Funktion , die wird ausgeführt, posix.read() Aufruf, und wird dann beenden, wie es auch zu Ende geführt hat. Schließlich, wenn die Ergebnisse der Lese verfügbar sind, wird die innerste Funktion ausgeführt werden.

Der wichtige Punkt ist, dass jede Funktion zur Fertigstellung läuft, da die Anrufe an den posix.*() Funktionen nicht blockierend sind: das heißt, sie sofort wieder, etwas Magie verursacht zu haben in dem zugrunde liegenden System gestartet wird ausgeschaltet. So jede Ihrer Funktionen beendet, und später ein Ereignis wird die nächste Funktion verursachen auszuführen; aber an keiner Stelle ist es eine Rekursion.

Die verschachtelte Struktur des Codes kann man den Eindruck, dass der Stoff, innen wird beenden müssen, bevor außerhalb des Stoff zu seinem eigenen Endpunkt erhalten. Aber in dieser Art von asynchroner ereignisgesteuerte Programmierung macht es mehr Sinn, die Verschachtelung in Bezug auf dem sehen tiefer => geschieht-später-als .

EDIT: Versuchen Sie, einige Logging-Anweisungen unmittelbar vor dem Ende jeder verschachtelten Funktion hinzugefügt; dies zu veranschaulichen helfen, dass die Reihenfolge, in der sie von außen nach innen ab.

Andere Tipps

Die gleiche Beispiel mit Debug-Ausgabe hinzugefügt (siehe unten für die Ausgabe):

usefile.js:

var sys = require("sys"),
  posix = require("posix");

var useFile = function(filename,callback){
    posix.stat(filename).addCallback(function (stats) {
        posix.open(filename, process.O_RDONLY, 0666).addCallback(function (fd) {
            posix.read(fd, stats.size, 0).addCallback(function(contents){
                callback(contents);
                sys.debug("useFile callback returned");
            });
            sys.debug("read returned");
        });
        sys.debug("open returned");
    });
    sys.debug("stat returned");
};

useFile("usefile.js",function(){});

Ausgabe:

DEBUG: stat returned
DEBUG: open returned
DEBUG: read returned
DEBUG: useFile callback returned

Sie können versuchen,

http://github.com/creationix/do

oder rollen Sie Ihre eigenen wie ich es tat. Nie jetzt fehlt Fehler dagegen Handling (einfach ignorieren, dass);)

var sys = require('sys');

var Simplifier = exports.Simplifier = function() {}

Simplifier.prototype.execute = function(context, functions, finalFunction) {
  this.functions = functions;
  this.results = {};
  this.finalFunction = finalFunction;
  this.totalNumberOfCallbacks = 0
  this.context = context;
  var self = this;

  functions.forEach(function(f) {
    f(function() {
      self.totalNumberOfCallbacks = self.totalNumberOfCallbacks + 1;
      self.results[f] = Array.prototype.slice.call(arguments, 0);     
      if(self.totalNumberOfCallbacks >= self.functions.length) {
        // Order the results by the calling order of the functions
        var finalResults = [];
        self.functions.forEach(function(f) {
          finalResults.push(self.results[f][0]);
        })
        // Call the final function passing back all the collected results in the right order 
        finalFunction.apply(self.context, finalResults);
      }
    });
  });
}

Und ein einfaches Beispiel mit it

// Execute 
new simplifier.Simplifier().execute(
  // Context of execution
  self,  
  // Array of processes to execute before doing final handling
  [function(callback) {
      db.collection('githubusers', function(err, collection) {
        collection.find({}, {limit:30}, function(err, cursor) {
          cursor.toArray(function(err, users) { callback(users); })
        });
      });      
    },

    function(callback) {
      db.collection('githubprojects', function(err, collection) {
        collection.find({}, {limit:45, sort:[['watchers', -1]]}, function(err, cursor) {
          cursor.toArray(function(err, projects) { callback(projects); })
        });
      });              
    }
  ],  
  // Handle the final result
  function(users, projects) {
    // Do something when ready
  }
);

Ihre Sachen sind in Ordnung. Ich mache rekursiven Aufrufe in Express HTTP folgen Umleitungen, aber was dein Werk ist „Traversal“ und nicht die Rekursion

Werfen Sie auch einen Blick auf 'step' ( http://github.com/creationix/step) oder 'Flow-js' auf gitHub. Auf diese Weise können Sie schreiben Rückruf fließt in einen natürlicheren Stil. Dies wird auch deutlich machen, dass es keine Rekursion geht.

Wie bei jedem JavaScript, ist es möglich, rekursive Aufrufe mit Node.js. machen Wenn Sie in Rekursionstiefe Probleme führen können (wie NickFitz weist darauf hin, Sie scheinen nicht in Gefahr, dass zu sein), können Sie oft neu schreiben Ihren Code ein Intervall-Timer, anstatt zu verwenden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top