在NodeJS中发送HTTP响应之前等待事件发生?

时间:2016-12-18 19:54:36

标签: node.js events asynchronous control-flow

我正在寻找在发送HTTP响应之前等待事件发生的解决方案。

使用案例

  1. 我的想法是在我的一条路线中调用一个函数:zwave.connect("/dev/ttyACM5");此函数立即返回。
  2. 但是,如果成功或无法连接设备,则存在2个事件:
  3. zwave.on('driver ready', function(){...});
    zwave.on('driver failed', function(){...});
    
    1. 在我的路线中,我想知道设备在发送HTTP响应之前是否成功或无法连接。
    2. 我的解决方案"

      1. 当事件发生时,我将事件保存在数据库中:
      2. zwave.on('driver ready', function(){
            //In the database, save the fact the event happened, here it's event "CONNECTED"
        });
        
        1. 在我的路线中,执行connect功能并等待事件发生 出现在数据库中:
        2. router.get('/', function(request, response, next) {     
              zwave.connect("/dev/ttyACM5");
              waitForEvent("CONNECTED", 5, null, function(){
                  response.redirect(/connected);
              });
          });
          
          // The function use to wait for the event
          waitForEvent: function(eventType, nbCallMax, nbCall, callback){
              if(nbCall == null) nbCall = 1;
              if(nbCallMax == null) nbCallMax = 1;
          
              // Looking for event to happen (return true if event happened, false otherwise
              event = findEventInDataBase(eventType);
          
              if(event){
                  waitForEvent(eventType, nbCallMax, nbCall, callback);
              }else{
                  setTimeout(waitForEvent(eventType, callback, nbCallMax, (nbCall+1)), 1500);
              }
          }
          

          我认为这不是一个好习惯,因为它会迭代对数据库的调用。 那么您对此有何意见/建议?

3 个答案:

答案 0 :(得分:8)

我已经开始将标记添加到您的问题中,因为在它的核心,这就是您要问的问题。 (另外,如果你不使用ES6,你应该能够将下面的代码翻译回ES5。)

TL; DR

有许多方法可以处理JavaScript中的异步控制流(另请参阅:What is the best control flow module for node.js?)。您正在寻找一种结构化的方式来处理它 - 可能是PromiseReactive Extensions for JavaScript (a.k.a RxJS)

使用Promise

的示例

来自MDN:

  

Promise 对象用于异步计算。 Promise表示现在或将来可用或永不可用的值。

在您的情况下,异步计算是计算描述连接到设备成功或失败的布尔值。为此,您可以将connect对象的调用封装在Promise对象中,如下所示:

const p = new Promise((resolve) => {
    // This assumes that the events are mutually exclusive
    zwave.connect('/dev/ttyACM5');
    zwave.on('driver ready', () => resolve(true));
    zwave.on('driver failed', () => resolve(false));
});

一旦有Promise表示连接状态,您就可以将功能附加到其未来"值:

// Inside your route file
const p = /* ... */;
router.get('/', function(request, response, next) {
    p.then(successful => {
        if (successful) {
            response.redirect('/connected');
        }
        else {
            response.redirect('/failure');
        }
    });
});

您可以详细了解Promises on MDN,或阅读有关该主题的众多其他资源之一(例如You're Missing the Point of Promises)。

答案 1 :(得分:3)

还有一个npm同步模块。用于同步执行查询的过程。

如果要以同步方式运行并行查询,则节点限制执行此操作,因为它永远不会等待响应。和同步模块非常适合这种解决方案。

示例代码

   /*require sync module*/
var Sync = require('sync');
    app.get('/',function(req,res,next){
      story.find().exec(function(err,data){
        var sync_function_data = find_user.sync(null, {name: "sanjeev"});
          res.send({story:data,user:sync_function_data});
        });
    });


    /*****sync function defined here *******/
    function find_user(req_json, callback) {
        process.nextTick(function () {

            users.find(req_json,function (err,data)
            {
                if (!err) {
                    callback(null, data);
                } else {
                    callback(null, err);
                }
            });
        });
    }

参考链接:https://www.npmjs.com/package/sync

答案 2 :(得分:2)

你试过这个吗?从它的外观来看,您的 zwave 可能已经实现了EventEmmiter,您只需要附加一个监听器

router.get('/', function(request, response, next) {     
    zwave.connect("/dev/ttyACM5");
    zwave.once('driver ready', function(){
        response.redirect(/connected);
    });
});