Vra

In Nodejs, is daar feitlik geen blokkeer I / O bedrywighede. Dit beteken dat byna al nodejs IO-kode behels baie verifikasie. Dit geld vir die lees en skryf na / van databasisse, lêers, prosesse, ens 'n Tipiese voorbeeld hiervan is die volgende:

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..
});

Ek verwag skryf kode wat baie IO bedrywighede sal maak, so ek verwag om te skryf baie verifikasie. Ek is baie gemaklik met behulp van verifikasie, maar ek is bekommerd oor al die rekursie. Is ek in gevaar van die bestuur in te veel rekursie en blaas deur 'n stapel iewers? As ek duisende individuele skryf aan my sleutel-waarde winkel met duisende verifikasie, sal my program uiteindelik crash?

Is ek misverstand of onderskat die impak? Indien nie, is daar 'n manier om te kry rondom dit terwyl nog steeds met behulp Nodejs 'terugbel kodering styl?

Was dit nuttig?

Oplossing

Nie een van die kode wat jy sien is die gebruik van rekursie. Wanneer jy useFile noem dit 'n beroep posix.stat(), wat terugkeer, en useFile beëindig as dit tot voltooiing. Op 'n sekere later tyd, wanneer die oproep om posix.stat() voltooi binne die onderliggende stelsel en die resultate is beskikbaar, die callback funksie wat jy bygevoeg vir wat uitgevoer sal word. Wat doen 'n beroep posix.open(), en dan eindig soos dit tot voltooiing. Sodra die lêer suksesvol oopgemaak, die callback funksie vir dat sal uit te voer, 'n beroep posix.read(), en sal dan beëindig as dit ook het tot voltooiing. Ten slotte, wanneer die resultate van die lees is beskikbaar, die binneste funksie sal uitgevoer word.

Die belangrike punt is dat elke funksie loop tot voltooiing, as die oproepe na die posix.*() funksies is nie-blokkeer: dit wil sê, hulle het dadelik terug te keer, 'n paar magic te begin in die onderliggende stelsel het veroorsaak. So elkeen van jou funksies beëindig, en later sal 'n gebeurtenis veroorsaak dat die volgende funksie uit te voer; maar op geen punt is daar geen rekursie.

Die geneste struktuur van die kode kan 'n mens die indruk dat die dinge binne-in sal hê om klaar te maak voordat die dinge buite sy eie eindpunt kan kry. Maar in hierdie styl van asynchrone gebeurtenis gedrewe programmering dit maak meer sin om die nes te sien in terme van dieper => gebeur-later-as .

EDIT: Probeer dadelik voeg 'n paar te meld state voor die einde van elke sub-funksie; Dit sal help om te illustreer dat die volgorde waarin hulle voltooi is van buite na binne.

Ander wenke

Dieselfde voorbeeld, met debug bygevoeg (sien hieronder vir uitvoer):

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(){});

Uitgawe:

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

Jy kan probeer

http://github.com/creationix/do

of rol jou eie soos ek gedoen het. Never mind ontbreek fout hantering vir nou (net ignoreer dat);)

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);
      }
    });
  });
}

En 'n eenvoudige voorbeeld om dit te gebruik

// 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
  }
);

Jou dinge is fyn. Ek doen rekursiewe oproepe in Express te volg HTTP wegwysbladsye, maar wat jy doen is "traversal" en nie rekursie

Neem ook 'n blik op 'n stap '( http://github.com/creationix/step) of 'vloei-js' op GitHub. Dit laat jou skryf terugbel vloei in 'n meer natuurlike styl. Dit sal ook maak dit duidelik dat daar geen rekursie aangaan.

Soos met enige JavaScript, dit is moontlik om rekursiewe oproepe met Node.js. maak As jy loop in rekursie diepte probleme (soos NickFitz wys daarop, het jy nie blyk te wees in gevaar van daardie), kan jy dikwels herskryf jou kode om 'n interval timer plaas gebruik.

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top