Comment empêcher Node.js de sortir en attendant un rappel?

J’ai un code comme celui-ci:

var client = new mysql.Client(options); console.log('Icanhasclient'); client.connect(function (err) { console.log('jannn'); active_db = client; console.log(err); console.log('hest'); if (callback) { if (err) { callback(err, null); } callback(null, active_db); } }); 

Mon problème est que le nœud se termine immédiatement lorsque je l’exécute. Il affiche “Icanhasclient”, mais aucun des fichiers console.log de l’appel n’est appelé.

(mysql dans cet exemple est node-mysql .

Peut-on faire quelque chose pour que node.js attende la fin du rappel avant de quitter?

Le rappel n’est pas en attente

Le nœud s’exécute jusqu’à ce que toutes les files d’attente d’ événements soient vides. Un rappel est ajouté à une file d’ événements lorsqu’un appel tel que

  emmiter1.on('this_event',callback). 

a exécuté. Cet appel fait partie du code écrit par le développeur du module.

Si un module est un port rapide à partir d’une version synchrone / bloquante, cela peut ne pas arriver jusqu’à ce qu’une partie de l’opération soit terminée et que toutes les files d’attente puissent se vider avant que cela ne se produise, permettant à un nœud de quitter silencieusement.

Il s’agit d’un bogue sournois que le développeur de modules peut ne pas rencontrer pendant le développement, car il se produira moins souvent dans les systèmes occupés avec de nombreuses files d’ attente, car il sera rare qu’ils soient tous vides au moment critique.

Un détecteur de correctif / bogue possible pour l’utilisateur consiste à insérer un événement de timer spécial avant l’appel de fonction suspect.

Vous pouvez simplement émettre un setTimeout ou un délai récurrent avec setInterval.

Si vous souhaitez vérifier les conditions de sortie, vous pouvez également effectuer un délai conditionnel:

 (function wait () { if (!SOME_EXIT_CONDITION) setTimeout(wait, 1000); })(); 

Mettez ceci à la fin de votre code et la console attendra juste… et attendra… jusqu’à ce que vous souhaitiez la fermer.

Ma solution consistait à instancier un EventEmitter et à écouter mon événement personnalisé.

 var eventEmitter = new process.EventEmitter(); 

alors j’ai appelé eventEmitter.emit du rappel async:

 client.connect(function (err) { eventEmitter.emit('myevent', {something: "Bla"}) }); 

La dernière chose dans mon script était l’ eventEmitter.on :

 eventEmitter.on('myevent', function(myResult){ // I needed the result to be written to stdout so that the calling process could get it process.stdout.write(JSON.ssortingngify(myResult)); }); 

Le nœud attendra alors que le gestionnaire d’événement se termine.

Basé sur la réponse de @ Todd, j’ai créé un one-liner. Incluez-le au début de votre script et définissez done = true lorsque vous avez terminé:

 var done = (function wait () { if (!done) setTimeout(wait, 1000) })(); 

Exemple:

 var done = (function wait () { if (!done) setTimeout(wait, 1000) })(); someAsyncOperation().then(() => { console.log('Good to go!'); done = true; }); 

Comment ça marche? Si nous développons un peu:

 // Initialize the variable `done` to `undefined` // Create the function wait, which is available inside itself // Note: `var` is hoisted but `let` is not so we need to use `var` var done = (function wait () { // As long as it's nor marked as done, create a new event+queue if (!done) setTimeout(wait, 1000); // No return value; done will resolve to false (undefined) })(); 

J’ai consulté la bibliothèque felixge / node-mysql et je n’ai pas vu de référence à la commande client.connect dans l’API. Est-ce l’appel réel que vous essayez de faire (n’essayez pas de faire la gueule ici)? Quoi qu’il en soit, à mon humble avis, vous devez réfléchir davantage à la manière dont Javascript est conçu, car il utilise un paradigme de programmation différent de la plupart des autres langages populaires.

Le premier problème que je vois dans votre code est que vous n’avez pas défini le rappel, il n’existe donc pas. Je suppose que console.log (callback) est indéfini. À partir de votre code, la fonction anonyme est le «rappel» de la fonction client.connect. Vous devez définir ce que vous appelez «rappel» à un niveau plus élevé. Par exemple, je définirai une fonction myCallback pour exister dans la scope supérieure à la fonction anonyme de client.connect. Il peut être utile de rechercher la scope de la variable Javacscript.

  var myCallback(err, response) { if (err) { console.log('err:%s',err); } else { console.log('response:%s',response); } } client.connect(err, function(response) { // this anonymous function is the callback to client.connect, the var // 'callback' would be undefined. if (err) { myCallback(err); return; // Explicit call to return, else the lines below would run. } myCallback(null, response); }); 

Deuxièmement, si vous n’appelez pas explicitement le retour dans Javascript, la fonction continuera à être traitée. J’ai été mordu par moi – même . Enfin, Javascript exécute une boucle pilotée par les événements, ce qui signifie qu’il n’attendra jamais que les fonctions renvoient une valeur, raison pour laquelle nous avons tous ces rappels. Vous pouvez forcer Javascript à se comporter différemment, par exemple en utilisant une boucle while jusqu’à ce qu’une condition soit vraie. Voir la bibliothèque ‘async’ par caolan , pour différentes stratégies de manipulation de la boucle d’événement. L’inconvénient majeur de l’utilisation excessive de ces méthodes est le fait que vous gaspillez vos cycles / blocages lorsque vous devez probablement utiliser davantage de rappels et simplement repenser le fonctionnement de vos programmes.