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

Ash*_*bay 4 events asynchronous control-flow node.js

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

用例

  1. 我的想法是在我的一个路由中调用一个函数:zwave.connect("/dev/ttyACM5");此函数立即返回.
  2. 但是有2个事件会注意到它是否成功或无法连接设备:
zwave.on('driver ready', function(){...});
zwave.on('driver failed', function(){...});
Run Code Online (Sandbox Code Playgroud)
  1. 在我的路线中,我想知道设备在发送HTTP响应之前是否成功或无法连接.

我的"解决方案"

  1. 当事件发生时,我将事件保存在数据库中:
zwave.on('driver ready', function(){
    //In the database, save the fact the event happened, here it's event "CONNECTED"
});
Run Code Online (Sandbox Code Playgroud)
  1. 在我的路由中,执行connect函数并等待事件出现在数据库中:
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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为这不是一个好习惯,因为它会迭代对数据库的调用.那么您对此有何看法?

Why*_*rrh 9

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

TL; DR

在JavaScript中有很多方法可以处理异步控制流(另请参阅:node.js的最佳控制流模块是什么?).您正在寻找一种结构化的方式来处理它 - 可能PromiseJavaScriptReactive Extensions for JavaScript(又名RxJS).

使用a的示例 Promise

来自MDN:

Promise对象用于异步计算.A 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));
});
Run Code Online (Sandbox Code Playgroud)

一旦Promise表示连接状态,就可以将函数附加到其"future"值:

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

您可以在MDN上了解有关Promises的更多信息,或者阅读有关该主题的许多其他资源之一(例如,您错过了承诺点).