如何编写一个node.js函数,在“返回”之前等待事件触发?

时间:2012-03-30 01:41:03

标签: javascript node.js asynchronous synchronous

我有一个节点应用程序一个Web应用程序 - 它在返回之前完成一系列异步任务1.在返回之前,程序的结果立即打印到控制台。

如何确保在返回之前完成所有异步工作?通过确保在调用res.end()之前完成的所有任务,我能够在Web应用程序中实现与此类似的功能,但在让脚本返回之前,我没有任何等效的最终“事件”。 / p>

请参阅下面的我(破损)功能,尝试等到callStack为空。我刚刚发现这是一种荒谬的方法,因为node在进入processObjWithRef中调用的任何异步函数之前等待processHub完成。

function processHub(hubFileContents){
    var callStack = [];
    var myNewObj = {};
    processObjWithRef(samplePayload, myNewObj, callStack);
    while(callStack.length>0){
        //do nothing
    }
    return 1
}

注意:我之前曾多次尝试使用像async这样的库来实现这种行为(请参阅How can I make this call to request in nodejs synchronous?上的相关问题)所以请在建议任何答案之前考虑答案和评论。只需使用asynch'。

6 个答案:

答案 0 :(得分:5)

你不能在返回之前等待异步事件 - 这是异步的定义!试图强制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中执行异步内容的常用方法是实现对函数的回调。

function processHub(hubFileContents, callback){
  var callStack = [];
  var myNewObj = {};
  processObjWithRef(samplePayload, myNewObj, callStack, function() {
    if (callStack.length == 0) {
      callback(some_results);
    }
  });
}

如果你真的想要退货,请查看promises;他们可以保证在解决后立即或在将来的某个时间点发出事件。

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

答案 1 :(得分:4)

deasync旨在准确解决您的问题。只需替换

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

require('deasync').loopWhile(function(){return callStack.length>0;});

答案 2 :(得分:3)

问题在于您的功能设计。您希望从异步执行的任务列表中返回同步结果。

您应该使用一个额外的参数来实现您的函数,该参数将是您将结果(在本例中为1)的回调,以供某些消费者使用它做一些事情。

此外,您需要在内部函数中使用回调参数,否则您将不知道它何时结束。如果最后这个不可能,那么你应该进行某种轮询(也许使用setInterval)来测试何时填充callStack数组。

请记住,在Javascript中你永远不应该忙着等待。这将完全锁定您的程序,因为它在单个进程上运行。

答案 3 :(得分:1)

问题是node.js是单线程的,这意味着如果一个函数运行,则在该函数返回之前没有其他任何东西运行(事件循环)。所以你不能阻止一个函数让它在异步完成之后返回。

例如,您可以设置一个计数器变量来计算启动的异步任务,并使用回调函数(在任务完成后调用该函数)从您的异步代码中减少该计数器。

答案 4 :(得分:1)

Node.js在A SINGLE线程事件循环上运行,并利用异步调用来执行各种操作,如I / O操作。

如果在执行其他代码之前需要等待多个异步操作完成 你可以尝试使用Async -

Node.js Async Tutorial

答案 5 :(得分:0)

你需要开始异步设计和思考,这可能需要一段时间才能习惯。这是一个简单的例子,说明如何在函数调用之后处理“返回”之类的事情。

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。