如何编写一个node.js函数,在'返回'

How to write a node.js function that waits for an event to fire before 'returning'?

本文关键字:函数 返回 js node 何编写 一个      更新时间:2023-09-26

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

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

请参阅下面的我的(坏的)函数,当前正在尝试等待callStack为空。我刚刚发现这是一种毫无意义的方法,因为节点在输入processObjWithRef中调用的任何异步函数之前都要等待processHub完成。

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

注意:我以前曾多次尝试使用async等库来实现这种行为(请参阅我在nodejs-synchronous中如何调用此请求?中的相关问题),因此在建议基于"仅使用async"的任何答案之前,请考虑其中的答案和注释。

不能等待异步事件才返回--这就是异步的定义!试图强迫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);
    }
  });
}

如果你真的想退货,看看承诺;它们被保证在解决后立即或在将来的某个时刻发出事件。

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)放在那里,让一些消费者用它做一些事情

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

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

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

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

带有

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

问题是node.js是单线程的,这意味着如果一个函数运行,则在该函数返回之前,不会运行其他函数(事件循环)。因此,您不能阻止一个函数,使其在异步操作完成后返回。

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

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

如果在执行附加代码之前需要等待大量异步操作完成你可以尝试使用异步

Node.js异步教程

您需要开始异步设计和思考,这可能需要一段时间才能适应。这是一个简单的例子,说明如何处理函数调用后的"返回"之类的问题。

function doStuff(param, cb) {
    //do something
    var newData = param;
    //"return"
    cb(newData);
}
doStuff({some:data}, function(myNewData) {
    //you're done with doStuff in here
});

npm上的异步库中还有很多有用的实用程序函数。