Как предотвратить выход Node.js во время ожидания обратного вызова? - PullRequest
80 голосов
/ 22 июня 2011

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

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 дождаться завершения обратного вызова перед выходом?

Ответы [ 5 ]

46 голосов
/ 26 декабря 2011

Обратный звонок не поставлен в очередь

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

  emmiter1.on('this_event',callback).

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

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

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

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

37 голосов
/ 29 апреля 2014

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

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

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

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

9 голосов
/ 21 июля 2017

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

var eventEmitter = new process.EventEmitter();

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

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

Последней вещью в моем сценарии была 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));
});

Затем узел будет ждать, пока обработчик событий не завершит свою работу.

2 голосов
/ 21 мая 2018

Основываясь на ответе @ Тодда, я создал однострочник. Включите его в начало вашего скрипта и установите 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's nor marked as done, create a new event+queue
  if (!done) setTimeout(wait, 1000);

  // No return value; done will resolve to false (undefined)
})();
0 голосов
/ 29 апреля 2012

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

Первая проблема, которую я вижу в вашем коде, заключается в том, что вы не определили обратный вызов, поэтому он на самом деле не существует.Я бы предположил, что console.log (callback) не определен.Из вашего кода анонимная функция является «обратным вызовом» для функции client.connect.Вы должны определить, что вы называете «обратным вызовом» в более широком контексте.Например, я определю функцию myCallback, которая будет существовать в области выше, чем анонимная функция client.connect.Это может быть полезно для поиска 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 запускает управляемый событиями цикл , означающий, что он никогда не будет ждать, пока функции вернут значение, поэтому у нас есть все эти обратные вызовы в первую очередь.Вы можете заставить Javascript вести себя по-другому, например, используя цикл while, пока условие не станет истинным.Смотрите библиотеку 'async' caolan , для различных стратегий манипулирования циклом событий.Основным недостатком чрезмерного использования этих методов является то, что вы фактически тратите циклы / блокировки ЦП, когда вам, вероятно, следует использовать больше обратных вызовов и просто переосмыслить работу своих программ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...