如何在Javascript中同步单独的回调

时间:2017-02-16 20:51:34

标签: javascript node.js rest express mqtt

我正在开发一个nodejs应用程序(使用express),它将通过HTTP为客户端提供REST调用。其中一个REST API将处理POST请求,该请求将从POST主体获取数据并通过MQTT客户端发布(作为应用程序的一部分启动)。

订阅主题的单独应用程序(通过我们都连接到的MQTT代理)我发布到将接收消息并通过向我的应用程序的MQTT客户端订阅的主题发布消息来响应(这将导致回调以在我的Javascript应用程序中触发。)

我希望能够在我的应用程序正在处理的POST响应中返回我的应用程序收到的MQTT消息。

在常规的“C语言编程”术语中......有一个处理REST API的线程和一个处理接收MQTT消息的独立线程(例如两个不同的套接字)。我想阻塞处理信号量上的POST处理线程的线程,直到MQTT线程可以接收一些数据,将其排队并释放信号量以解除对POST处理线程的阻塞(然后将消息出列并将其返回到POST回复)。

在修改各种模块和Promise / Generators之后,我不清楚如何让它工作......

这样做的“javascript方式”是什么?

TIA!

3 个答案:

答案 0 :(得分:1)

你没有在node.js中阻止。通过它的设计,node.js是事件驱动的,并且所有网络I / O(以及大多数文件I / O)都是非阻塞和异步的。因此,您需要协调多个异步操作,并在两者完成时得到通知(带有某种事件)。

当你没有共享任何代码时,很难非常具体,但是现在协调异步操作的主要工具是承诺。因此,如果您使每个异步操作返回一个将在异步操作完成时解析的promise或在异步操作遇到错误时拒绝,那么您可以使用Promise.all()两个promise,它会告诉您当两个异步操作都完成并为你提供两个结果时。

一般的想法是:

 let p1 = asyncOperation1(...);
 let p2 = asyncOperation2(...);

 Promise.all([p1, p2]).then(results => {
     // both async operations are done here
     // results[0] and results[1] contain the resolved value of each of the two promises
 }).catch(err => {
     // process error here
 });

为了从REST操作获得承诺,有许多不同的解决方案,从手动执行您自己的运营承诺包装,到包装请求模块的模块,向像Bluebird这样具有.promisify()的库提供承诺和.promisifyAll()方法为您自动包装操作。要提供有关如何从异步操作中获得承诺的更具体信息,您必须与您分享实际代码。

因为看起来你是新来的,让我提供一些发布建议。如果您向我们展示您的代码,我们将始终能够提供更完整和更相关的答案。当你没有向我们展示你的代码时,你实际上是在寻求一个通用的教程,这个教程要写得多,而且更难以确保它涵盖你的确切用例。

答案 1 :(得分:1)

最终发现我可能已经在考虑解决方案......

在POST处理回调中,我将响应对象排入队列并返回。稍后,在MQTT订阅消息处理回调中,我将挂起的响应对象出列,并使用它向挂起的POST事务发送正确的响应。

答案 2 :(得分:0)

请勿阻止,在您发布的邮件中包含唯一ID,并且响应邮件也包含此ID。

然后使用此id作为密钥将快速响应对象存储在对象中,以便当响应到达并发回响应时。

您还应该包含一个时间戳,以便您可以定期遍历等待的响应对象,并在MQTT消息未及时到达时进行响应。

var onGoingRequests = {};
var id = 0;

mqttClient.on('message',function(topic,message){
  var payload = JSON.parse(message.toString());
  var details = onGoingRequest[payload.id];
  if (details) {
    details.response.status(200).send(details.body);
    delete onGoingRequests[payload.id];
  } else {
    //response too late
  }
});

app.post('/foo', function(req, resp) {
    var message = {
      id: 'foo' +id++,
      body: req.body
    }
    var topic = 'request/foo'; 
    mqttClient.publish(topic, JSON.stringify(message));
    onGoingRequests[message.id] = {
      response: resp,
      timestamp: Date.now(),
    }; 
});

var timeout = setInterval(function(){
  var now = Date.now();
  var keys = Object.keys(onGoingCommands);
  for (key in keys){
    var waiting = onGoingCommands[keys[key]];
    if (waiting) {
      var diff = now - waiting.timestamp;
      if (diff < timeout) {
        waiting.res.status(504).send('{"error": "timeout"}');
        delete onGoingCommands[keys[key]];
      }
    }
  }
}, 500);