with starting start parse nodejs node new how create javascript recursion callback node.js v8

javascript - starting - Gestionando mucha recursividad de devolución de llamada en Nodejs



starting with node (6)

Como con cualquier JavaScript, es posible hacer llamadas recursivas con Node.js. Si tiene problemas de profundidad de recursión (como señala NickFitz, no parece estar en peligro de eso), a menudo puede volver a escribir su código para usar un temporizador de intervalos.

En Nodejs, prácticamente no hay operaciones de bloqueo de E / S. Esto significa que casi todo el código de IO de nodejs implica muchas devoluciones de llamada. Esto se aplica a la lectura y escritura a / desde bases de datos, archivos, procesos, etc. Un ejemplo típico de esto es el siguiente:

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

Estoy anticipando el código de escritura que hará muchas operaciones de E / S, por lo que espero estar escribiendo muchas devoluciones de llamada. Estoy bastante cómodo con el uso de devoluciones de llamada, pero estoy preocupado por todas las recursiones. ¿Estoy en peligro de sufrir demasiada recursión y soplar a través de una pila en alguna parte? Si hago miles de escrituras individuales en mi almacén de valor clave con miles de devoluciones de llamada, ¿se bloqueará mi programa con el tiempo?

¿Estoy malinterpretando o subestimando el impacto? Si no es así, ¿hay alguna manera de evitar esto mientras aún usas el estilo de codificación de devolución de llamada de Nodejs?


Mismo ejemplo, con salida de depuración agregada (ver más abajo para salida):

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

Salida:

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


Ninguno de los códigos que muestres está usando recursión. Cuando llama a useFile , llama a posix.stat() , que devuelve, y useFile termina a medida que se ejecuta hasta su finalización. En algún momento posterior, cuando la llamada a posix.stat() haya completado dentro del sistema subyacente y los resultados estén disponibles, se ejecutará la función de devolución de llamada que agregó. Eso llama a posix.open() , y luego termina cuando se ejecuta hasta su finalización. Una vez que el archivo se haya abierto con éxito, la función de devolución de llamada para eso se ejecutará, llamando a posix.read() , y luego terminará, ya que también se ha ejecutado hasta su finalización. Finalmente, cuando los resultados de la lectura estén disponibles, se ejecutará la función más interna.

El punto importante es que cada función se ejecuta hasta que se completa, ya que las llamadas a las funciones posix.*() No se bloquean: es decir, regresan de inmediato, lo que provocó que se iniciara algo de magia en el sistema subyacente. Entonces, cada una de tus funciones termina, y luego un evento hará que la siguiente función se ejecute; pero en ningún momento hay recursión.

La estructura anidada del código puede dar la impresión de que las cosas que hay que terminar deben terminar antes de que las cosas de fuera puedan llegar a su propio punto final. Pero en este estilo de programación asincrónica basada en eventos, tiene más sentido ver el anidamiento en términos de más profundo => sucede más tarde que .

EDITAR: intente agregar algunas instrucciones de registro inmediatamente antes del final de cada función anidada; Esto ayudará a ilustrar que el orden en que se completan es desde el exterior hacia adentro.


Puedes probar

http://github.com/creationix/do

o enrolla el tuyo como lo hice yo. No importa perder el manejo de errores por ahora (solo ignóralo);)

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

Y un simple ejemplo usándolo.

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


También eche un vistazo a ''step'' ( http://github.com/creationix/step ) o ''flow-js'' en github. Esto le permite escribir flujos de devolución de llamada en un estilo más natural. Esto también dejará claro que no hay recursión.


Tus cosas están bien. Hago llamadas recursivas en Express para seguir las redirecciones HTTP, pero lo que haces es "transversal" y no recursivo