我有一个简化的函数,看起来像这样:

function(query) {
  myApi.exec('SomeCommand', function(response) {
    return response;
  });
}

我想让它调用myApi。Exec,返回回调lambda中给出的响应。然而,上面的代码不能工作,只是立即返回。

只是为了一个非常hack的尝试,我尝试了下面的工作,但至少你知道我想要实现什么:

function(query) {
  var r;
  myApi.exec('SomeCommand', function(response) {
    r = response;
  });
  while (!r) {}
  return r;
}

基本上,“node.js/事件驱动”的好方法是什么?我希望我的函数等待,直到回调被调用,然后返回传递给它的值。


当前回答

注意:这个答案可能不应该在产品代码中使用。这是一个黑客,你应该知道它的含义。

有uvrun模块(这里更新了较新的Nodejs版本),您可以在其中执行libuv主事件循环(这是Nodejs主循环)的单个循环。

你的代码应该是这样的:

function(query) {
  var r;
  myApi.exec('SomeCommand', function(response) {
    r = response;
  });
  var uvrun = require("uvrun");
  while (!r)
    uvrun.runOnce();
  return r;
}

你也可以使用uvrun.runNoWait()。这可以避免一些阻塞问题,但占用100%的CPU。)

注意,这种方法在某种程度上否定了Nodejs的整个目的,即让所有内容都是异步和非阻塞的。此外,它可能会大大增加调用堆栈的深度,因此可能会导致堆栈溢出。如果你递归地运行这样的函数,你肯定会遇到麻烦。

请参阅其他关于如何重新设计代码以使其“正确”的答案。

这里的解决方案可能只在您进行测试时有用,特别是当您想要同步和串行代码时。

其他回答

从节点4.8.0开始,您可以使用ES6中称为生成器的特性。 您可以通过本文了解更深入的概念。 但基本上你可以使用生成器和承诺来完成这项工作。 我使用蓝鸟承诺和管理发电机。

您的代码应该就像下面的示例一样。

const Promise = require('bluebird');

function* getResponse(query) {
  const r = yield new Promise(resolve => myApi.exec('SomeCommand', resolve);
  return r;
}

Promise.coroutine(getResponse)()
  .then(response => console.log(response));

“好的node.js /事件驱动”的方法是不要等待。

与node等事件驱动系统一样,函数应该接受一个回调参数,该参数将在计算完成时被调用。调用者不应该等待正常意义上的值被“返回”,而是发送将处理结果值的例程:

function(query, callback) {
  myApi.exec('SomeCommand', function(response) {
    // other stuff here...
    // bla bla..
    callback(response); // this will "return" your value to the original caller
  });
}

所以你不能这样使用它:

var returnValue = myFunction(query);

但就像这样:

myFunction(query, function(returnValue) {
  // use the return value here instead of like a regular (non-evented) return value
});

这违背了非阻塞IO的目的——你在不需要阻塞的时候阻塞了它:)

你应该嵌套回调,而不是强迫node.js等待,或者在需要r结果的回调中调用另一个回调。

如果您需要强制阻塞,那么很可能您对体系结构的想法是错误的。

使用async和await要容易得多。

router.post('/login',async (req, res, next) => {
i = await queries.checkUser(req.body);
console.log('i: '+JSON.stringify(i));
});

//User Available Check
async function checkUser(request) {
try {
    let response = await sql.query('select * from login where email = ?', 
    [request.email]);
    return response[0];

    } catch (err) {
    console.log(err);

  }

}

检查: https://github.com/luciotato/waitfor-ES6

您的代码与等待。对于:(需要生成器,——和谐旗)

function* (query) {
  var r = yield wait.for( myApi.exec, 'SomeCommand');
  return r;
}