グローバル イベント エミッターを使用して Node.js アプリケーションを作成しています。つまり、私のアプリケーションは完全にイベントを中心に構築されています。この種のアーキテクチャは、ここで説明する 1 つの副次的なケースを除いて、私にとって非常にうまく機能していると思います。
この質問に答えるのに Node.js の知識は必要ないと思います。したがって、私はそれを抽象化しようとします。
次の状況を想像してください。
- グローバル イベント エミッタ ( と呼ばれる
mediator
) を使用すると、個々のモジュールがアプリケーション全体のイベントをリッスンできます。 - 着信要求を受け入れる HTTP サーバーが作成されます。
- 着信リクエストごとに、このリクエストに固有のイベントを処理するイベント エミッターが作成されます。
着信リクエストの例 (純粋にこの質問を説明するため):
mediator.on('http.request', request, response, emitter) {
//deal with the new request here, e.g.:
response.send("Hello World.");
});
ここまでは順調ですね。要求された URL を識別し、適切なイベントを発行することで、このアプリケーションを拡張できます。
mediator.on('http.request', request, response, emitter) {
//identify the requested URL
if (request.url === '/') {
emitter.emit('root');
}
else {
emitter.emit('404');
}
});
これに続いて、ルート要求を処理するモジュールを作成できます。
mediator.on('http.request', function(request, response, emitter) {
//when root is requested
emitter.once('root', function() {
response.send('Welcome to the frontpage.');
});
});
いいですね。実際には、コードが壊れている可能性があります。その理由は、行emitter.emit('root')
が行の前に実行される可能性があるためですemitter.once('root', ...)
。その結果、リスナーが実行されることはありません。
root
イベントの発行をイベント ループの最後まで遅らせることで、この特定の状況に対処できます。
mediator.on('http.request', request, response, emitter) {
//identify the requested URL
if (request.url === '/') {
process.nextTick(function() {
emitter.emit('root');
});
}
else {
process.nextTick(function() {
emitter.emit('404');
});
}
});
これが機能する理由は、現在のイベント ループが終了するまでエミッションが遅延され、すべてのリスナーが登録されるためです。
ただし、このアプローチには多くの問題があります。
- このようなイベント ベースのアーキテクチャの利点の 1 つは、発行モジュールが、誰がイベントをリッスンしているかを知る必要がないことです。したがって、イベントの発行を遅らせる必要があるかどうかを判断する必要はありません。なぜなら、何がイベントをリッスンするのか、それを遅らせる必要があるかどうかがわからないからです。
- コードが大幅に乱雑になり、複雑になります (2 つの例を比較してください)。
- おそらくパフォーマンスが低下します
結果として、私の質問は次のとおりです。説明した状況のように、イベントの発行をイベントループの次のティックに遅らせる必要をどのように回避しますか?
2013 年 1 月 19 日更新
この動作が役立つ理由を示す例: http 要求を並行して処理できるようにするため。
mediator.on('http.request', function(req, res) {
req.onceall('json.parsed', 'validated', 'methodoverridden', 'authenticated', function() {
//the request has now been validated, parsed as JSON, the kind of HTTP method has been overridden when requested to and it has been authenticated
});
});
各イベントjson.parsed
が元のリクエストを発行する場合、各イベントは別のリクエストに関連しており、特定のリクエストに対して並行して実行されるアクションの組み合わせをリッスンできないため、上記は不可能です。