Async: "Taille maximale de la pile d'appels dépassée" à l'aide de async.forEachLimit

Créé le 26 déc. 2011  ·  15Commentaires  ·  Source: 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);
});

Enregistrer

$ 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

Commentaire le plus utile

Je faisais une opération de synchronisation. Je l'ai corrigé en changeant de:

callback();

pour

setTimeout(callback, 0);

Tous les 15 commentaires

forEachLimit semble faux.

started += 1 running += 1

doit être déplacé devant l'appel de l'itérateur. arr[started] devrait également être remplacé par arr[started - 1]

Remarque : Vous ne rencontrerez ce bogue que si le code à l'intérieur de l'itérateur appelle le rappel dans le même tick.

ARRÊTER d'appeler les fonctions SYNC dans async.js

J'ai rencontré ce problème lorsque j'avais un conditionnel return callback(null); dans mon itérateur. Cela signifiait que je devais faire la chose la plus intelligente, qui consiste à filtrer le tableau en utilisant Array.filter avant d'appliquer async.forEach , donc c'était plutôt utile...

Si vous pensez _vraiment_ que vous devriez le faire, vous pouvez contourner ce problème en utilisant process.nextTick(function() { callback(); }) .

@jacobrask Cela a bien fonctionné. Merci

Faire callback(null); est synchrone. Vous devez l'appeler de manière asynchrone, ala process.nextTick(callback) ou process.nextTick(function() { callback(null); }); . Comme @bobrik l' a dit, arrêtez d'appeler les fonctions de synchronisation en asynchrone :)

Dire "arrêter d'appeler les fonctions de synchronisation en asynchrone" manque le point - c'est cassé, et ce n'est que dans forEachLimit que cela semble être un problème.

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

Bien que je puisse assez facilement me protéger contre cet exemple très spécifique (comme @jacobrask le mentionne en filtrant), que se passe-t-il si doStuff() (qui peut se trouver dans une bibliothèque hors de mon contrôle) décide d'appeler mon rappel sans process.nextTick() ?

J'ai ajouté du code pour appeler async.nextTick s'il détecte un itérateur synchrone qui devrait éviter un débordement de pile dans ces cas. Mais sérieusement, ARRÊTEZ D'APPELER LES FONCTIONS DE SYNC EN ASYNC ! ...rendez vos fonctions toujours synchrones ou toujours asynchrones à la place ;)

Cela m'est également arrivé avec async.eachSeries .

Se produit également dans mapLimit , et oui ma fonction est synchronisée car c'est une fonction fictive. Ensuite, je l'enveloppe dans le setImmediate , le problème est résolu.

Arrive avec moi sur async.forEachOfLimit

Face au même problème avec async.waterfall .

async.queue aussi, bien sûr.

Je faisais une opération de synchronisation. Je l'ai corrigé en changeant de:

callback();

pour

setTimeout(callback, 0);

Cela m'est arrivé quand j'avais un hic attaché à une promesse. Quelque chose comme:
async.forEach(items, (item:any, callback:Function) => { someAsyncPromise(item).then(() => { callback(); }).catch((err) => { //console error or something here callback(); }) });

catch doit être lancé avant le bit async dans la promesse, car cette erreur n'est lancée que lorsqu'une exception s'est produite dans la promesse.

`

Je comprends que nous devrions arrêter d'appeler les fonctions de synchronisation en asynchrone.

Mais, si l'appel de la fonction de synchronisation callback() dans le corps asynchrone est erroné, pourquoi la documentation asynchrone le montre-t-elle dans les exemples ?

Quelqu'un peut-il m'aider à comprendre quelle est la "bonne" façon de travailler avec le module asynchrone à la place ?

Voici un exemple tiré directement de la documentation async :

// 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

Merci!

Cette page vous a été utile?
0 / 5 - 0 notes