Async: 'Tamanho máximo da pilha de chamadas excedido' usando async.forEachLimit

Criado em 26 dez. 2011  ·  15Comentários  ·  Fonte: 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);
});

Registro

$ 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

Comentários muito úteis

Eu estava fazendo uma operação de sincronização. Eu consertei mudando de:

callback();

para

setTimeout(callback, 0);

Todos 15 comentários

forEachLimit parece errado.

started += 1 running += 1

deve ser movido na frente da chamada do iterador. arr[started] também deve ser alterado para arr[started - 1]

Nota: Você só encontrará esse bug se o código dentro do iterator iterator chamar o retorno de chamada no mesmo tick.

PARAR de chamar funções SYNC em async.js

Eu encontrei esse problema quando eu tinha um condicional return callback(null); no meu iterador. Isso significava que eu tinha que fazer a coisa mais inteligente, que é filtrar o array usando Array.filter antes de aplicar async.forEach , então foi realmente útil ...

Se você _realmente_ acha que deveria, você pode contornar isso usando process.nextTick(function() { callback(); }) .

@jacobrask Isso funcionou bem. Obrigado

Fazer callback(null); é síncrono. Você precisa chamá-lo de forma assíncrona, ala process.nextTick(callback) , ou process.nextTick(function() { callback(null); }); . Como @bobrik disse, pare de chamar funções de sincronização em assíncrona :)

Dizer "parar de chamar funções de sincronização em assíncrono" está perdendo o ponto - está quebrado e é apenas em forEachLimit que isso parece ser um problema.

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

Embora eu possa facilmente me proteger contra esse exemplo muito específico (como @jacobrask menciona filtrando), e se doStuff() (que pode estar em uma biblioteca fora do meu controle) decidir chamar meu retorno de chamada sem um process.nextTick()?

Eu adicionei algum código para chamar async.nextTick se ele detectar um iterador síncrono que deve evitar um estouro de pilha nesses casos. Mas falando sério, PARE DE CHAMAR FUNÇÕES DE SINCRONIZAÇÃO EM ASYNC! ...torna suas funções consistentemente síncronas ou consistentemente assíncronas ;)

Isso também aconteceu comigo com async.eachSeries .

Também acontece em mapLimit , e sim minha função é sync porque é uma função mock. Então eu envolvo no setImmediate , o problema resolvido.

Acontece comigo em async.forEachOfLimit

Enfrentando o mesmo problema com async.waterfall .

async.queue também, é claro.

Eu estava fazendo uma operação de sincronização. Eu consertei mudando de:

callback();

para

setTimeout(callback, 0);

Isso aconteceu comigo quando eu tinha uma pegadinha ligada a uma promessa. Algo como:
async.forEach(items, (item:any, callback:Function) => { someAsyncPromise(item).then(() => { callback(); }).catch((err) => { //console error or something here callback(); }) });

catch deve ser lançado antes do bit assíncrono na promessa, porque esse erro é gerado somente quando a exceção ocorre na promessa.

`

Eu entendo que devemos parar de chamar funções de sincronização em assíncrono.

Mas, se chamar a função de sincronização callback() dentro do corpo assíncrono estiver errado, por que a documentação assíncrona mostra isso nos exemplos?

Alguém pode me ajudar a entender qual é a maneira 'correta' de trabalhar com o módulo assíncrono?

Aqui está um exemplo diretamente da documentação assí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

Obrigado!

Esta página foi útil?
0 / 5 - 0 avaliações