Как написать функцию node.js, которая ожидает события, чтобы сработать, прежде чем «вернуться»? - PullRequest
10 голосов
/ 30 марта 2012

У меня есть приложение узла, которое не веб-приложение - оно выполняет серию асинхронных задач перед возвратом 1. Непосредственно перед возвратом результаты программы выводятся на консоль.

Как мне убедиться, что вся асинхронная работа завершена перед возвратом?Мне удалось добиться чего-то подобного в веб-приложении, убедившись, что все задачи, которые мы выполнили до вызова res.end (), но у меня нет эквивалента для вызова окончательного «события», прежде чем позволить скрипту вернуться.

См. Ниже мою (сломанную) функцию в настоящее время, пытаясь дождаться, пока callStack опустеет.Я только что обнаружил, что это своего рода бессмысленный подход, потому что узел ожидает завершения processHub, прежде чем вводить какую-либо асинхронную функцию, вызываемую в processObjWithRef.поведения с библиотеками, такими как async (см. мой связанный вопрос на Как я могу сделать этот вызов для запроса в nodejs синхронным? ), поэтому, пожалуйста, примите во внимание ответ и комментарии там, прежде чем предлагать какие-либо ответы, основанные на «просто использовать»асинхронный.

Ответы [ 6 ]

5 голосов
/ 30 марта 2012

Вы не можете ждать асинхронного события перед возвратом - это определение асинхронного!Попытка принудить Node к этому стилю программирования причинит вам только боль.Наивным примером будет периодически проверять, является ли callstack пустым.

var callstack = [...];

function processHub(contents) {
  doSomethingAsync(..., callstack);
}

// check every second to see if callstack is empty
var interval = setInterval(function() {
  if (callstack.length == 0) {
    clearInterval(interval);
    doSomething()
  }
}, 1000);

Вместо этого обычным способом выполнения асинхронных операций в Node является реализация обратного вызова вашей функции.1006 *

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

function processHub(hubFileContents){
  var callStack = [];
  var myNewObj = {};
  var promise = new Promise();

  // assuming processObjWithRef takes a callback
  processObjWithRef(samplePayload, myNewObj, callStack, function() {
    if (callStack.length == 0) {
      promise.resolve(some_results);
    }
  });

  return promise;
}

processHubPromise = processHub(...);
processHubPromise.then(function(result) {
  // do something with 'result' when complete
});
4 голосов
/ 24 декабря 2014

deasync предназначен для точного решения вашей проблемы.Просто замените

while(callStack.length>0){
    //do nothing
}

на

require('deasync').loopWhile(function(){return callStack.length>0;});
3 голосов
/ 30 марта 2012

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

Вы должны реализовать свою функцию с дополнительным параметром, который будет обратным вызовом, в который вы положили бы результат (в данном случае 1)для какого-то потребителя, чтобы что-то с ним сделать.

Также вам нужно иметь параметр обратного вызова во внутренней функции, иначе вы не будете знать, когда он закончится.Если это последнее невозможно, то вам следует выполнить какой-либо опрос (возможно, используя setInterval), чтобы проверить, заполнен ли массив callStack.

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

1 голос
/ 25 декабря 2014

Node.js запускается в ОДНОМ поточном цикле событий и использует асинхронные вызовы для выполнения различных задач, например операций ввода-вывода.

, если вам нужно дождаться завершения ряда асинхронных операций перед выполнением дополнительного кода Вы можете попробовать использовать Async -

Руководство по асинхронной работе Node.js

1 голос
/ 30 марта 2012

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

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

0 голосов
/ 30 марта 2012

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

function doStuff(param, cb) {
    //do something
    var newData = param;
    //"return"
    cb(newData);
}

doStuff({some:data}, function(myNewData) {
    //you're done with doStuff in here
});

В библиотеке async также доступно множество полезных служебных функций, доступных на npm..

...