Как предотвратить Node.js от выхода во время ожидания обратного вызова?

У меня такой код:

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);
  }
});

Моя проблема в том, что Node завершается сразу же после запуска. Он печатает "Icanhasclient", но ни один из console.log внутри обратного вызова не вызван.

(mysql в этом примере node-mysql.

Есть ли что-то, что можно сделать, чтобы сделать node.js ждать завершения обратного вызова до выхода?

Ответ 1

Обратный вызов не находится в очереди

Node выполняется до тех пор, пока все события очереди не будут пустыми. Обратный вызов добавляется в очередь событий , когда вызов, например

  emmiter1.on('this_event',callback).

выполнено. Этот вызов является частью кода, написанного разработчиком модуля.

Если модуль является быстрым портом из синхронной/блокирующей версии, это может не произойти до завершения какой-либо части операции, и все очереди могут быть опущены до того, как это произойдет, что позволит node выйти молча.

Это непроницаемая ошибка, то есть такая, которую разработчик модуля может не запускать во время разработки, поскольку это будет происходить реже в занятых системах со многими очередями, поскольку это будет редкость для всех они должны быть пустыми в критический момент.

Возможным детектором ошибок/ошибок для пользователя является вставка специального события таймера перед вызовом подозрительной функции.

Ответ 2

Вы можете просто выдать setTimeout или повторяющийся таймаут с помощью setInterval.

Если вы хотите проверить условия выхода, вы также можете выполнить условный тайм-аут:

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

Поместите это в конец вашего кода, и консоль просто подождет... и подождите... пока вы не захотите его закрыть.

Ответ 3

Мое решение заключалось в создании экземпляра EventEmitter и прослушивании моего пользовательского события.

var eventEmitter = new process.EventEmitter();

то я вызвал eventEmitter.emit из асинхронного обратного вызова:

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

Последнее, что в моем script было 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));
});

Node будет ждать окончания выполнения обработчика событий.

Ответ 4

На основании ответа @Todd я создал однострочник. Включите его в начало вашего скрипта и установите done = true когда вы закончите:

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

Пример:

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

someAsyncOperation().then(() => {
  console.log('Good to go!');
  done = true;
});

Как это работает? Если мы немного расширим его:

// 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 nor marked as done, create a new event+queue
  if (!done) setTimeout(wait, 1000);

  // No return value; done will resolve to false (undefined)
})();

Ответ 5

Мне интересно, почему никто не разместил ответ, который вообще не блокирует!

const http = require('http');
http.createServer((req, res) => {
  res.end('');
}).listen(3000, function() {
        console.log("listening on port 3000, don't expect any response :-)");
});

Это заставит Node.js ждать и прослушивать порт 3000, создавая сервер, который ничего не делает (таким образом, ожидает и вообще не блокирует)

Ответ 6

Вот мои два цента:

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)));

Ответ 7

Я просмотрел felixge/node-mysql библиотеку и не видел ссылку на команду client.connect в API. Это реальный вызов, который вы пытаетесь сделать (не пытаясь быть нелепым здесь)? Независимо от того, IMHO, вам нужно больше думать о том, как разрабатывается Javascript, потому что он использует парадигму программирования, отличную от большинства других популярных языков.

Первая проблема, которую я вижу в вашем коде, заключается в том, что вы не определили обратный вызов, поэтому он фактически не существует. Я бы предположил, что console.log(callback) - undefined. Из вашего кода анонимная функция является "обратным вызовом" для функции client.connect. Вы должны определить, что вы вызываете "обратный вызов" в более высокой области. Например, я определю функцию myCallback для существования в области выше, чем функция client.connect anonymous. Может быть полезно найти 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);
    });

Во-вторых, если вы явно не вызываете return внутри Javascript, функция будет продолжать обрабатываться. Я был укушен этим . Наконец, Javascript запускает цикл event-driven, поскольку он никогда не будет ждать возврата функций, поэтому мы имеем все эти обратные вызовы в первое место. Вы можете заставить Javascript вести себя по-другому, например, используя цикл while, пока условие не будет истинным. См. "Асинхронную" библиотеку caolan для различных стратегий управления циклом событий. Основным недостатком использования этих методов является то, что вы фактически тратите процессорные циклы/блокирование, когда вам, вероятно, следует использовать больше обратных вызовов и просто переосмыслить, как работают ваши программы.

Ответ 8

Пожалуйста, попробуйте это. Проверьте, поможет ли это.

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);
    })
}