Async: 'Se excedió el tamaño máximo de la pila de llamadas' usando async.forEachLimit

Creado en 26 dic. 2011  ·  15Comentarios  ·  Fuente: caolan/async

async = require('async');

var documents = ['a', 'b', 'c', 'd', 'e', 'f'];

async.forEachLimit(documents, 2, function(item, callback) {
  console.log(".", item);
  callback(null);
}, function(err){
  console.log("end", err);
});

Tronco

$ node test.js
. a
. a
. a
. a
. a
. a
end undefined
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
[...]

node.js:134
        throw e; // process.nextTick error, or 'error' event on first tick
        ^
RangeError: Maximum call stack size exceeded

Comentario más útil

Estaba haciendo una operación de sincronización. Lo arreglé cambiando de:

callback();

para

setTimeout(callback, 0);

Todos 15 comentarios

forEachLimit se ve mal.

started += 1 running += 1

debe moverse delante de la llamada al iterador. arr[started] también debe cambiarse a arr[started - 1]

Nota: Solo encontrará este error si el código dentro del iterador iterador llama a la devolución de llamada en el mismo tic.

DEJA de llamar a las funciones SYNC en async.js

Encontré este problema cuando tenía un return callback(null); condicional en mi iterador. Significaba que tenía que hacer lo más inteligente, que es filtrar la matriz usando Array.filter antes de aplicar async.forEach , por lo que en realidad fue útil...

Si _realmente_ cree que debería hacerlo, puede solucionarlo usando process.nextTick(function() { callback(); }) .

@jacobrask Eso funcionó bien. Gracias

Hacer callback(null); es sincrónico. Debe llamarlo de forma asíncrona, ala process.nextTick(callback) o process.nextTick(function() { callback(null); }); . Como dijo @bobrik , deja de llamar a las funciones de sincronización en asíncrono :)

Decir "dejar de llamar a las funciones de sincronización en asíncrono" no tiene sentido: está roto y solo en forEachLimit parece ser un problema.

async.forEachLimit(['a','b'], 1, function(item, callback){
  if(something) {
    doStuff(function(){ callback(); });
  } else {
    callback();
  }
});

Si bien puedo protegerme bastante fácilmente contra ese ejemplo muy específico (como @jacobrask menciona al filtrar), ¿qué pasa si doStuff() (que podría estar en una biblioteca fuera de mi control) decide llamar a mi devolución de llamada sin un proceso.nextTick()?

Agregué un código para llamar a async.nextTick si detecta un iterador síncrono que debería evitar un desbordamiento de pila en estos casos. Pero en serio, ¡DEJA DE LLAMAR FUNCIONES DE SINCRONIZACIÓN EN ASYNC! ... haga que sus funciones sean consistentemente sincrónicas o consistentemente asincrónicas en su lugar;)

Esto también me sucedió con async.eachSeries .

También sucede en mapLimit , y sí, mi función está sincronizada porque es una función simulada. Luego lo envuelvo en setImmediate , el problema está resuelto.

Sucede conmigo en async.forEachOfLimit

Enfrentando el mismo problema con async.waterfall .

async.queue, también, por supuesto.

Estaba haciendo una operación de sincronización. Lo arreglé cambiando de:

callback();

para

setTimeout(callback, 0);

Esto me sucedió cuando tenía una trampa adjunta a una promesa. Algo como:
async.forEach(items, (item:any, callback:Function) => { someAsyncPromise(item).then(() => { callback(); }).catch((err) => { //console error or something here callback(); }) });

catch debe lanzarse antes del bit asíncrono en la promesa, porque este error solo se lanza cuando ocurre una excepción en la promesa.

`

Entiendo que deberíamos dejar de llamar a las funciones de sincronización de forma asíncrona.

Pero, si llamar a la función de sincronización devolución de llamada () dentro del cuerpo asíncrono es incorrecto, ¿por qué la documentación asíncrona muestra eso en los ejemplos?

¿Puede alguien ayudarme a entender cuál es la forma 'correcta' de trabajar con el módulo asíncrono?

Aquí hay un ejemplo directamente de la documentación asíncrona:

// assuming openFiles is an array of file names
async.each(openFiles, function(file, callback) {

    // Perform operation on file here.
    console.log('Processing file ' + file);

    if( file.length > 32 ) {
      console.log('This file name is too long');
      callback('File name too long');
    } else {
      // Do work to process file here
      console.log('File processed');
      callback();
    }
}, function(err) {
    // if any of the file processing produced an error, err would equal that error
    if( err ) {
      // One of the iterations produced an error.
      // All processing will now stop.
      console.log('A file failed to process');
    } else {
      console.log('All files have been processed successfully');
    }
});

https://caolan.github.io/async/docs.html#each

¡Gracias!

¿Fue útil esta página
0 / 5 - 0 calificaciones