ノードでは、多くのオブジェクトがイベントを放出します。たとえば、TCPサーバーは、クライアントが接続を要求するたびに「接続」イベントを送信します。たとえば、データ全体が読み取られるときはいつでも、ファイルシステムは「データ」イベントを送信します。これらのオブジェクトは、ノードのイベントエミッターと呼ばれます。イベントトランスミッターにより、プログラマーは関心のあるイベントを購読し、コールバック関数を関連イベントに結合できるため、イベントトランスミッターがイベントを発するたびにコールバック関数が呼び出されます。パブリッシュ/サブスクライブモードは、ボタンがクリックされたときに対応する通知を受信するなど、従来のGUIモードと非常に似ています。このモデルを使用して、クライアント接続、ソケットで利用可能なデータ、または閉じたファイルなど、一部のイベントが発生するとサーバープログラムが反応する可能性があります。
独自のイベントトランスミッターを作成することもできます。実際、Nodeは、独自のイベントトランスミッターを作成するためのベースクラスとして使用できる特別なEventeMitter擬似クラスを提供します。
コールバックモードを理解します
非同期プログラミングは、関数の戻り値を使用して関数呼び出しの終了を示すのではなく、その後のパススタイルを採用します。
「Continuation-Passing Style」(CPS:Continuation-Passing Style)はプログラミングスタイルであり、プロセス制御は次の操作に明示的に渡されます...
CPSスタイルの関数は、関数を追加パラメーターとして受け入れます。この関数は、プログラム制御の次のプロセスを明示的に指摘するために使用されます。 CPS関数が「戻り値」を計算すると、プログラムの次のプロセスを表す関数を呼び出し、CPS関数の「戻り値」をパラメーターとして取得します。
Wikipediaから-http://en.wikipedia.org/wiki/continuation-passing_style
このプログラミングスタイルでは、各関数は実行後にコールバック関数を呼び出し、プログラムが実行され続けることができます。 JavaScriptはこのプログラミングスタイルに非常に適していることを後で理解するでしょう。以下は、ノードの下のメモリにファイルをロードする例です。
コードコピーは次のとおりです。
var fs = require( 'fs');
fs.readfile( '/etc/passwd'、function(err、filecontent){
if(err){
エラーを投げます。
}
console.log( 'file content'、filecontent.toString());
});
この例では、fs.readfileの2番目のパラメーターとしてインライン匿名関数を渡します。実際、これはCPSプログラミングを使用しています。これは、プログラム実行の後続のプロセスをコールバック関数に引き渡すためです。
ご覧のとおり、コールバック関数の最初のパラメーターはエラーオブジェクトです。プログラムでエラーが発生した場合、このパラメーターはエラークラスのインスタンスになります。これは、ノードのCPSプログラミングの一般的なパターンです。
イベントトランスミッターモードを理解します
標準のコールバックモードでは、機能が実行される関数のパラメーターとして渡されます。このモードは、機能が完了した後にクライアントに通知する必要があるシナリオで非常にうまく機能します。ただし、関数の実行中に複数のイベントが発生するか、イベントが複数回発生する場合、このパターンは適切ではありません。たとえば、ソケットが利用可能なデータを受信するたびに通知を取得する場合、このシナリオでは標準のコールバックモードがあまり役に立たないことがわかります。この時点で、イベントトランスミッターモードは役立ちます。一連の標準インターフェイスを使用して、イベントジェネレーターとイベントリスナーを明確に分離できます。
イベントジェネレーターモードを使用する場合、2つ以上のオブジェクトが関与しています。イベントトランスミッターと1つ以上のイベントリスナーです。
イベント送信機は、名前が示すように、イベントを生成できるオブジェクトです。イベントリスナーは、次の例のように、特定の種類のイベントをリッスンするためにイベントトランスミッターにバインドされています。
コードコピーは次のとおりです。
var req = http.request(options、function(response){
Response.on( "data"、function(data){
console.log( "応答からの一部のデータ"、データ);
});
Response.on( "end"、function(){
console.log( "Response Ended");
});
});
req.end();
このコードは、NodeのHTTP.Request APIを使用してリモートHTTPサーバーにアクセスするためにHTTP要求を作成するときに2つの必要な手順を示します(後の章を参照)。ファーストラインは、「継続パススタイル」(CPS:継続パススタイル)を採用し、HTTPが応答したときに呼び出されるインライン関数を渡します。 HTTPリクエストAPIは、HTTP.Request関数が実行された後も後続の操作を実行し続ける必要があるため、ここでCPSを使用します。
HTTP.Requestが実行されると、匿名のコールバック関数が呼び出され、HTTP応答オブジェクトがパラメーターとして渡されます。このHTTP応答オブジェクトは、イベントトランスミッターです。ノードドキュメントによると、データや終了など、多くのイベントを放出できます。登録するコールバック関数は、イベントが発生するたびに呼び出されます。
レッスンとして、要求された操作が完了した後に実行権を取り戻す必要がある場合はCPSモードを使用し、イベントが複数回発生する可能性がある場合にイベントトランスミッターモードを使用します。
イベントタイプを理解します
送信されたイベントには、文字列で表されるタイプがあります。前の例には、イベントトランスミッターによって定義された文字列である「データ」と「エンド」の2つのイベントタイプが含まれています。ただし、イベントタイプは通常、空の文字が含まれていない小文字で構成されていることが従来的に構成されています。
イベントトランスミッタAPIには内省メカニズムがないため、イベントトランスミッタが生成できるイベントの種類を推測することはできません。そのため、使用しているAPIには、これらのタイプのイベントを放出できることを示すドキュメントが必要です。
イベントが発生すると、イベントトランスミッターはイベントに関連するリスナーを呼び出し、関連するデータをパラメーターとしてリスナーに渡します。前の例http.requestでは、「データ」イベントコールバック関数は、データオブジェクトを最初の唯一のパラメーターとして受け入れ、「end」はデータを受け入れません。 API契約の一部としてのこれらのパラメーターは、APIの著者によって主観的に定義されています。これらのコールバック関数のパラメーター署名は、各イベントエミッタのAPIドキュメントでも説明されます。
イベントトランスミッターはあらゆる種類のイベントを提供するインターフェイスですが、「エラー」イベントはノードでの特別な実装です。ノードのほとんどのイベント送信機は、プログラムでエラーが発生すると「エラー」イベントを生成します。プログラムがイベントトランスミッターの「エラー」イベントを聞かない場合、イベントトランスミッターは、エラーが発生したときにconged excevaugdの例外を上方にスローします。
Node Perlで次のコードを実行して効果をテストできます。これは、2つのイベントを生成できるイベントトランスミッターをシミュレートできます。
コードコピーは次のとおりです。
var em = new(require( 'events')。eventemitter)();
em.emit( 'event1');
em.emit( 'error'、new Error( 'My Mistar'));
次の出力が表示されます。
コードコピーは次のとおりです。
var em = new(require( 'events')。eventemitter)();
未定義
> em.emit( 'event1');
間違い
> em.emit( 'error'、new Error( 'My Mistor'));
エラー:私の間違い
REPL:1:18
replserver.eval(repl.js:80:21)で
Repl.jsで:190:20
replserver.eval(repl.js:87:5)
インターフェイス。<anonymous>(repl.js:182:12)
interface.emit(events.js:67:17)
interface._online(readline.js:162:10)
interface._line(readline.js:426:8)
interface._ttywrite(readline.js:603:14)
ReadStream。<anonymous>(readline.js:82:12)
>
コードの2行目では、「Event1」と呼ばれるイベントが放出されますが、効果はありませんが、「エラー」イベントが発現すると、エラーがスタックにスローされます。プログラムがPERLコマンドライン環境で実行されていない場合、プログラムは、猛かけられていない例外のためにクラッシュします。
イベント送信機APIを使用します
イベントトランスミッターモード(TCPソケット、HTTPリクエストなど)を実装するオブジェクトは、次のメソッドセットを実装します。
コードコピーは次のとおりです。
.addlistener and .on-指定されたタイプのイベントにイベントリスナーを追加します
.Once-指定されたタイプのイベントで1回しか実行されないイベントリスナーをバインドします
.RemoveEventListener-指定されたイベントにバインドされたリスナーを削除します
.removealleventlistener-指定されたイベントにバインドされているすべてのリスナーを削除します
以下に詳細に紹介しましょう。
.addlistener()または.on()を使用したバインディングコールバック関数
イベントタイプとコールバック関数を指定することにより、イベントが発生したときに実行されるアクションを登録できます。たとえば、ファイルがデータストリームを読み取るときに利用可能なデータブロックがある場合、「データ」イベントが発生します。次のコードは、コールバック関数に合格する方法を示して、データイベントが発生したことをプログラムに伝えさせます。
コードコピーは次のとおりです。
function Receiveata(data){
console.log( "ファイル読み取りストリーム:%j"、data)からデータを取得します);
}
readstream.addlistener( "data"、receiveata);
.onを使用することもできます。これは、.addlistenerの略語です。次のコードは上記と同じです。
コードコピーは次のとおりです。
function Receiveata(data){
console.log( "ファイル読み取りストリーム:%j"、data)からデータを取得します);
}
readstream.on( "data"、receiveata);
前のコードでは、コールバック関数として事前に定義された名前の機能を使用することもできます。また、インライン匿名関数を使用してコードを簡素化することもできます。
コードコピーは次のとおりです。
readstream.on( "data"、function(data){
console.log( "ファイル読み取りストリーム:%j"、data)からデータを取得します);
});
前述のように、コールバック関数に渡されるパラメーターと署名の数は、特定のイベントトランスミッターオブジェクトとイベントタイプによって異なります。それらは標準化されていません。 「データ」イベントは、データバッファオブジェクトを渡す場合があり、「エラー」イベントはエラーオブジェクトを渡し、データフローの「終了」イベントはイベントリスナーにデータを渡しません。
複数のイベントリスナーをバインドします
イベントトランスミッターモードを使用すると、複数のイベントリスナーが同じイベントタイプの同じイベントトランスミッターをリッスンすることができます。
コードコピーは次のとおりです。
ここにいくつかのデータがあります。
ここにもいくつかのデータがあります。
イベントトランスミッターは、指定されたイベントタイプにバインドされているすべてのリスナーを、リスナーが登録されている順序で呼び出す責任があります。
1.イベントが発生した場合、イベントリスナーはすぐに呼び出されず、その前に他のイベントリスナーが呼ばれる場合があります。
2。スタックにスローされることは異常です。これは、コードのバグのためかもしれません。イベントが送信されると、イベントリスナーが呼び出されたときに例外をスローする場合、一部のイベントリスナーは決して呼ばれない場合があります。この場合、イベントトランスミッターは例外をキャッチし、それを処理することもできます。
次の例を参照してください。
コードコピーは次のとおりです。
readstream.on( "data"、function(data){
新しいエラーをスローします(「何か間違ったことが起こった」);
});
readstream.on( "data"、function(data){
console.log( 'ここにもいくつかのデータがあります。');
});
最初のリスナーは例外をスローするため、2番目のリスナーは呼び出されません。
.removelistener()を使用して、イベントトランスミッターからイベントリスナーを削除します
オブジェクトのイベントを気にしなくなった場合は、このようなイベントタイプとコールバック関数を指定することで、登録されたイベントリスナーをキャンセルできます。
コードコピーは次のとおりです。
function Receiveata(data){
console.log( "ファイル読み取りストリーム:%j"、data)からデータを取得します);
}
readstream.on( "data"、receiveata);
// ...
readstream.removelistener( "data"、receiveata);
この例では、最後の行では、イベントトランスミッターオブジェクトから将来いつでも呼び出されるイベントリスナーを削除します。
リスナーを削除するには、コールバック関数に名前を付ける必要があります。これは、コールバック関数の名前が追加および削除されるときに必要であるためです。
.once()を使用して、コールバック関数を最大で1回実行できるようにします
せいぜい1回実行されるイベントを聞きたい場合、またはイベントが初めて発生したときにのみ興味がある場合は、.once()関数を使用できます。
コードコピーは次のとおりです。
function Receiveata(data){
console.log( "ファイル読み取りストリーム:%j"、data)からデータを取得します);
}
readstream.once( "data"、receiveata);
上記のコードでは、受信した関数は1回のみ呼び出されます。 ReadStreamオブジェクトがデータイベントを発した場合、受信したコールバック関数は一度だけトリガーされます。
このように、非常に簡単に実装できるため、実際には便利な方法です。
コードコピーは次のとおりです。
var eventemitter = require( "events")。eventemitter;
eventemitter.prototype.once = function(type、callback){
var that = this;
this.on(type、functionリスナー(){
that.removelistener(タイプ、リスナー);
callback.apply(それ、引数);
});
};
上記のコードでは、eventemitter.prototype.once関数を再定義し、eventemitterから継承された各オブジェクトの一度関数を再定義します。コードは、.on()メソッドを単純に使用します。イベントを受信したら、.removeEventListener()を使用して、コールバック関数の登録をキャンセルし、元のコールバック関数を呼び出します。
注:以前のコードは、function.apply()メソッドを使用します。これは、オブジェクトを受け入れ、この変数とパラメーターの配列を含むものとして使用します。前の例では、変更されていないパラメーター配列が、イベントトランスミッターを介してコールバック関数に透過的に渡されます。
.removealllisteners()を使用したイベントトランスミッターからすべてのイベントリスナーを削除します
次のように、指定されたイベントタイプに登録されたすべてのリスナーをイベントトランスミッターから削除できます。
コードコピーは次のとおりです。
emitter.removealllisteners(タイプ);
たとえば、このようなすべてのプロセス割り込み信号のリスナーをキャンセルできます。
コードコピーは次のとおりです。
process.Removealllisteners( "Sigterm");
注:レッスンとして、削除されたものを正確に知っている場合にのみこの関数を使用することをお勧めします。それ以外の場合は、アプリケーションの他の部分にイベントリスナーコレクションを削除するか、プログラムのそれらの部分がリスナー自身を削除することを担当させることもできます。しかし、何があっても、この関数は、イベント送信機を閉鎖したり、プロセス全体を整然とシャットダウンする準備をしている場合など、いくつかのまれなシナリオでも役立ちます。
イベント送信機を作成します
イベントトランスミッターは、プログラミングインターフェイスを優れた方法でより一般的にします。一般的で理解しやすいプログラミングモードでは、クライアントはさまざまな機能を直接呼び出しますが、イベントトランスミッターモードでは、クライアントはさまざまなイベントにバインドされているため、プログラムがより柔軟になります。 (翻訳者のメモ:この文はあまり自信がありません。元のテキストを投稿します。イベントエミッターは、プログラミングインターフェイスをより一般的にする素晴らしい方法を提供します。一般的な理解パターンを使用すると、クライアントは関数を呼び出す代わりにイベントにバインドし、プログラムをより柔軟にします。)
さらに、イベントトランスミッターを使用すると、同じイベントで複数の無関係なリスナーをバインドするなど、多くの機能を取得することもできます。
ノードイベントトランスミッターから継承されます
ノードのイベントエミッターモードに興味があり、独自のアプリケーションで使用する予定の場合は、EventeMitterを継承して擬似クラスを作成できます。
コードコピーは次のとおりです。
util = require( 'util');
var eventemitter = require( 'events')。eventemitter;
//これはMyClassのコンストラクターです:
var myclass = function(){
}
util.inherits(myclass、eventemitter);
注:Util.Inheritsは、MyClassのプロトタイプチェーンを作成して、MyClassインスタンスがEventEmitterのプロトタイプメソッドを使用できるようにします。
起動イベント
EventeMitterから継承することにより、MyClassは次のようなイベントを起動できます。
コードコピーは次のとおりです。
myclass.prototype.somemethod = function(){
this.emit( "カスタムイベント"、 "引数1"、 "引数2");
};
上記のコードでは、MyClassインスタンスでSomeMethondメソッドが呼び出されると、「Cuthom Event」と呼ばれるイベントが排出されます。このイベントは、「引数1」と「引数2」という2つの文字列をデータとして発します。これは、イベントリスナーのパラメーターとして渡されます。
MyClassインスタンスのクライアントは、次のような「カスタムイベント」イベントを聞くことができます。
コードコピーは次のとおりです。
var myInstance = new MyClass();
myInstance.on( 'カスタムイベント'、function(str1、str2){
console.log( 'str1%sおよびstr2%s!'、str1、str2でカスタムイベントがありました);
});
たとえば、1秒に1回「ティック」イベントを発するティッカークラスを作成できます。
コードコピーは次のとおりです。
var util = require( 'util')、
eventemitter = require( 'events')。eventemitter;
var ticker = function(){
var self = this;
setInterval(function(){
self.emit( 'tick');
}、1000);
};
util.inherits(ティッカー、eventemitter);
ティッカークラスを使用しているクライアントは、ティッカークラスの使用方法を示し、「ティック」イベントを聞くことができます。
コードコピーは次のとおりです。
var ticker = new Ticker();
Ticker.on( "tick"、function(){
console.log( "tick");
});
まとめ
イベントトランスミッターモードは、特定のイベントのコードセットからイベントトランスミッターオブジェクトを分離するために使用できる再移行パターンです。
event_emitter.on()を使用して、特定のタイプのイベントにリスナーを登録し、event_emitter.removelistener()で登録していません。
また、EventeMitterを継承し、.emit()関数を使用するだけで独自のイベントEmitterを作成することもできます。