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

Tri*_*daz 10 javascript asynchronous synchronous node.js

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

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

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

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

注意:我曾多次尝试使用async之类的库来实现这种行为(请参阅我的相关问题如何在nodejs中同步调用此请求?)所以请在建议之前考虑答案和注释答案基于'只是使用asynch'.

Mic*_*ley 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);
Run Code Online (Sandbox Code Playgroud)

相反,在Node中执行异步内容的常用方法是实现对函数的回调.

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

如果你真的想要归还某些东西,请查看承诺 ; 他们保证在解决时立即或在将来的某个时间点发出事件.

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
});
Run Code Online (Sandbox Code Playgroud)


Leo*_*spo 4

问题出在你的功能设计上。您想要从异​​步执行的任务列表中返回同步结果。

您应该使用一个额外的参数来实现您的函数,该参数将是回调,您将在其中放置结果(在本例中为 1),以便某些消费者对其执行某些操作。

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

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

  • 投了反对票,因为这没有回答问题。在某些情况下,您可能会编写一个小型命令行程序或一个 AWS Lambda,而您并不关心主线程是否被阻塞。 (2认同)