Tengo un código como este:
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);
}
});
Mi problema es que Node termina inmediatamente cuando lo ejecuto. Imprime 'Icanhasclient', pero no se llama a ninguno de los console.log's dentro de la devolución de llamada.
(mysql en este ejemplo es node-mysql .
¿Hay algo que se pueda hacer para que node.js espere a que se complete la devolución de llamada antes de salir?

Respuestas:
La devolución de llamada no está en cola
El nodo se ejecuta hasta que todas las colas de eventos están vacías. Se agrega una devolución de llamada a una cola de eventos cuando una llamada como
emmiter1.on('this_event',callback).ha ejecutado. Esta llamada es parte del código escrito por el desarrollador del módulo.
Si un módulo es un puerto rápido de una versión síncrona / de bloqueo, es posible que esto no suceda hasta que se haya completado una parte de la operación y todas las colas se vacíen antes de que eso suceda, permitiendo que el nodo salga silenciosamente.
Este es un error furtivo, que el desarrollador del módulo podría no encontrar durante el desarrollo, ya que ocurrirá con menos frecuencia en sistemas ocupados con muchas colas, ya que será raro que todos estén vacíos en el momento crítico.
Un posible detector de corrección / error para el usuario es insertar un evento de temporizador especial antes de la llamada a la función sospechosa.
fuente
EventEmitter.on()no sin añadir nada al bucle de eventos que nodo esperará a que (al menos en la versión actual del nodo). Parece que solo cosas como establecer tiempos de espera y realizar llamadas asíncronas desde la biblioteca central pueden hacer esto. Puede probar esto fácilmente escribiendo un programa de una línea que espera un evento que nunca se disparará. A partir de esta respuesta, se espera también que nunca se termina, sino que lo hace termina al instante. Consulte esta respuesta para obtener más información.Puede simplemente emitir un setTimeout o un tiempo de espera recurrente con setInterval.
Si desea verificar las condiciones de salida, también puede hacer un tiempo de espera condicional:
(function wait () { if (!SOME_EXIT_CONDITION) setTimeout(wait, 1000); })();Pon esto al final de tu código y la consola simplemente esperará ... y esperará ... hasta que quieras que se cierre.
fuente
Mi solución fue crear una instancia de un EventEmitter y escuchar mi evento personalizado.
var eventEmitter = new process.EventEmitter();luego llamé
eventEmitter.emitdesde la devolución de llamada asíncrona:client.connect(function (err) { eventEmitter.emit('myevent', {something: "Bla"}) });Lo último en mi guión fue
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.stringify(myResult)); });El nodo esperará hasta que el controlador de eventos termine de ejecutarse.
fuente
EventEmitterla clase está definida por eleventsmódulo. Por lo tanto, para crear un nuevo emisor:const EventEmitter = require('events'); var eventEmitter = new EventEmitter().Basado en la respuesta de @ Todd, creé una sola línea. Inclúyelo al principio de tu guión y configúralo
done = truecuando hayas terminado:var done = (function wait () { if (!done) setTimeout(wait, 1000) })();Ejemplo:
var done = (function wait () { if (!done) setTimeout(wait, 1000) })(); someAsyncOperation().then(() => { console.log('Good to go!'); done = true; });¿Como funciona? Si lo ampliamos un poco:
// 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) })();fuente
Aquí están mis dos centavos:
async function main() { await new Promise(function () {}); console.log('This text will never be printed'); } function panic(error) { console.error(error); process.exit(1); } // https://stackoverflow.com/a/46916601/1478566 main().catch(panic).finally(clearInterval.bind(null, setInterval(a=>a, 1E9)));fuente
Así es como lo hago. Hago que mi punto de entrada principal devuelva una promesa, luego uso este pequeño contenedor para asegurarme de que mientras esa promesa no se cumpla, el nodo no saldrá:
function wrapPromiseMain(entryPoint) { const pollTime = 1000000; let interval = setInterval(() => {}, pollTime); return entryPoint().finally(() => {clearInterval(interval)}); }Para usarlo, simplemente prometa su punto de entrada principal y páselo como argumento al contenedor:
function main() { // ... main stuff ... return doSomethingAsync(); } wrapPromiseMain(main);Lo encuentro un poco más ordenado que los bucles de sondeo básicos porque cancelará automáticamente el temporizador cuando se establezca la promesa, por lo que no agrega ninguna latencia adicional. Por lo tanto, el tiempo de votación puede ser básicamente para siempre si así lo desea.
fuente
Miré la biblioteca felixge / node-mysql y no vi una referencia al comando client.connect en la API. ¿Es esta la llamada real que está tratando de hacer (no tratando de ser quisquilloso aquí)? Independientemente, en mi humilde opinión, debe pensar más en cómo está diseñado Javascript, porque utiliza un paradigma de programación diferente a la mayoría de los otros lenguajes populares.
El primer problema que veo en su código es que no ha definido la devolución de llamada, por lo que en realidad no existe. Asumiría que console.log (devolución de llamada) no está definido. Desde su código, la función anónima es la 'devolución de llamada' para la función client.connect. Debe definir lo que está llamando "devolución de llamada" en un ámbito superior. Por ejemplo, definiré una función myCallback para que exista en el alcance más alto que la función anónima de client.connect. Puede resultar útil buscar el alcance 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); });En segundo lugar, si no llama explícitamente a return dentro de Javascript, la función continuará procesándose. Me picaron por este mismo . Finalmente, Javascript ejecuta un bucle controlado por eventos, lo que significa que nunca esperará a que las funciones devuelvan un valor, por lo que tenemos todas estas devoluciones de llamada en primer lugar. Puede forzar que Javascript se comporte de manera diferente, por ejemplo, usando un ciclo while hasta que una condición sea verdadera. Consulte la biblioteca 'async' de caolan , para conocer varias estrategias de manipulación del bucle de eventos. La principal desventaja del uso excesivo de estos métodos es que en realidad está desperdiciando ciclos / bloqueos de CPU cuando probablemente debería usar más devoluciones de llamada y simplemente repensar cómo funcionan sus programas.
fuente
Por favor intente esto. Compruebe si esto ayuda.
var client = new mysql.Client(options); console.log('Icanhasclient'); var verbose; if (!verbose) { return new Promise(function (resolve, reject) { client.connect(function (err) { if (err) { console.log(Error in connecting SQL ${err} ) ; return reject(err); } verbose = client; return resolve(verbose); }) }) } else { return new Promise(function (resolve) { resolve(verbose); }) }fuente