このチュートリアルでは、Node.js のネイティブ EvenEmitter
クラスについて学びます。コースを完了すると、イベント、EvenEmitter
の使用方法、およびプログラムでのイベントの利用方法を理解できるようになります。さらに、EventEmitter
クラスが他のローカル モジュールからどのように拡張されるのかを学び、いくつかの例を通じてその背後にある原則を理解します。
推奨チュートリアル: node js チュートリアル
つまり、この記事では EventEmitter
クラスに関するすべてを説明します。
イベント駆動型のアーキテクチャは現在非常に一般的であり、イベント駆動型のプログラムはさまざまなイベントを生成、検出し、それに応答できます。
Node.js のコア部分はイベント駆動型であり、ファイル システム (fs
) や stream
などの多くのモジュール自体が EventEmitter # を使用します。 ## によって書かれた。
Event (event) は、ユーザーの操作やセンサーのタイミング出力など、1 つ以上のアクションの結果です。
イベント駆動型プログラムは、パブリッシャーがイベントをトリガーし、サブスクライバーがイベントをリッスンして適切なアクションを実行する、パブリッシュ/サブスクライブ モデルとして考えることができます。 たとえば、ユーザーが画像をアップロードできるサーバーがあるとします。イベント駆動型プログラミングでは、画像のアップロードなどのアクションによってイベントが発行され、それを利用するために 1 ~ n 人のサブスクライバーも発生します。 アップロード イベントがトリガーされた後、サブスクライバーは、サイトの管理者に電子メールを送信することで、サイトの管理者に通知し、対応することができます。別のサブスクライバーは、アクションに関する情報を収集し、データベースに保存することができます。 これらのイベントは通常、互いに独立していますが、相互に依存する場合もあります。 イベントエミッターとは何ですか?EventEmitter クラスは、
events モジュールにある Node.js の組み込みクラスです。ドキュメントの説明によると:
Function オブジェクト (「リスナー」) への呼び出しが発生します。"
このクラスは、パブリッシュ/サブスクライブ モデルとしてある程度記述することができます。補助ツールの実装は、イベント エミッター ( Create EventEmittersそうは言っても、EventEmitter を作成する方がより現実的です。これを行うには、クラス自体のインスタンスを作成するか、カスタム クラスを通じて実装してから、クラスのインスタンスを作成します。
EventEmitter を作成します。
events から開始します。モジュール内の EventEmitter
クラス: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">const { EventEmitter } = require('events');</pre><div class="contentsignin">ログイン後にコピー</div></div>
次に、
: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">const timerEventEmitter = new EventEmitter();</pre><div class="contentsignin">ログイン後にコピー</div></div>
このオブジェクトを使用してイベントを公開します。簡単:
timerEventEmitter.emit("update");
イベント名は以前に指定されており、イベントとして発行されました。しかし、まだこのイベントに反応するリスナーがいないため、プログラムは応答しませんでした。
最初にこのイベントを 1 秒ごとに繰り返します。## を使用してください。 #setInterval()
メソッドを使用してタイマーを作成し、update イベントを 1 秒ごとに発行します:
let currentTime = 0; // 每秒触发一次 update 事件 setInterval(() => { currentTime++; timerEventEmitter.emit('update', currentTime); }, 1000);
EventEmitter インスタンスはイベント名を受け入れるために使用され、パラメータ。イベント名として update を渡し、プログラム開始からの時間として
currentTime を渡します。
emit( )
timerEventEmitter.on('update', (time) => { console.log('从发布者收到的消息:'); console.log(`程序已经运行了 ${time} 秒`); });
via
on() メソッドはリスナーを作成し、イベントを渡しますリスナーをアタッチするイベントを指定する名前。update イベントで、時間を記録するメソッドを実行します。
on()
コードを実行すると、次の出力が出力されます:
从发布者收到的消息: 程序已经运行了 1 秒 从发布者收到的消息: 程序已经运行了 2 秒 从发布者收到的消息: 程序已经运行了 3 秒 ...
once()
メソッドを使用してサブスクライブすることもできます:timerEventEmitter.once('update', (time) => { console.log('从发布者收到的消息:'); console.log(`程序已经运行了 ${time} 秒`); });
このコードを実行すると、出力:
从发布者收到的消息: 程序已经运行了 1 秒
EventEmitter
複数のリスナーを使用する場合#end
: カウントダウン終了時にトリガー : カウントダウン終了の 2 秒前にトリガー
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">const countDown = (countdownTime) => {
const eventEmitter = new EventEmitter();
let currentTime = 0;
// 每秒触发一次 update 事件
const timer = setInterval(() => {
currentTime++;
eventEmitter.emit('update', currentTime);
// 检查计时是否已经结束
if (currentTime === countdownTime) {
clearInterval(timer);
eventEmitter.emit('end');
}
// 检查计时是否会在 2 秒后结束
if (currentTime === countdownTime - 2) {
eventEmitter.emit('end-soon');
}
}, 1000);
return eventEmitter;
};</pre><div class="contentsignin">ログイン後にコピー</div></div>
<p>这个函数启动了一个每秒钟发出一次 <code>update
事件的事件。
第一个 if
用来检查计时是否已经结束并停止基于间隔的事件。如果已结束将会发布 end
事件。
如果计时没有结束,那么就检查计时是不是离结束还有 2 秒,如果是则发布 end-soon
事件。
向该事件发射器添加一些订阅者:
const myCountDown = countDown(5); myCountDown.on('update', (t) => { console.log(`程序已经运行了 ${t} 秒`); }); myCountDown.on('end', () => { console.log('计时结束'); }); myCountDown.on('end-soon', () => { console.log('计时将在2秒后结束'); });
这段代码将会输出:
程序已经运行了 1 秒 程序已经运行了 2 秒 程序已经运行了 3 秒 计时将在2秒后结束 程序已经运行了 4 秒 程序已经运行了 5 秒 计时结束
接下来通过扩展 EventEmitter
类来实现相同的功能。首先创建一个处理事件的 CountDown
类:
const { EventEmitter } = require('events'); class CountDown extends EventEmitter { constructor(countdownTime) { super(); this.countdownTime = countdownTime; this.currentTime = 0; } startTimer() { const timer = setInterval(() => { this.currentTime++; this.emit('update', this.currentTime); // 检查计时是否已经结束 if (this.currentTime === this.countdownTime) { clearInterval(timer); this.emit('end'); } // 检查计时是否会在 2 秒后结束 if (this.currentTime === this.countdownTime - 2) { this.emit('end-soon'); } }, 1000); } }
可以在类的内部直接使用 this.emit()
。另外 startTimer()
函数用于控制计时开始的时间。否则它将在创建对象后立即开始计时。
创建一个 CountDown
的新对象并订阅它:
const myCountDown = new CountDown(5); myCountDown.on('update', (t) => { console.log(`计时开始了 ${t} 秒`); }); myCountDown.on('end', () => { console.log('计时结束'); }); myCountDown.on('end-soon', () => { console.log('计时将在2秒后结束'); }); myCountDown.startTimer();
运行程序会输出:
程序已经运行了 1 秒 程序已经运行了 2 秒 程序已经运行了 3 秒 计时将在2秒后结束 程序已经运行了 4 秒 程序已经运行了 5 秒 计时结束
on()
函数的别名是 addListener()
。看一下 end-soon
事件监听器:
myCountDown.on('end-soon', () => { console.log('计时将在2秒后结束'); });
也可以用 addListener()
来完成相同的操作,例如:
myCountDown.addListener('end-soon', () => { console.log('计时将在2秒后结束'); });
此函数将以数组形式返回所有活动的侦听器名称:
const myCountDown = new CountDown(5); myCountDown.on('update', (t) => { console.log(`程序已经运行了 ${t} 秒`); }); myCountDown.on('end', () => { console.log('计时结束'); }); myCountDown.on('end-soon', () => { console.log('计时将在2秒后结束'); }); console.log(myCountDown.eventNames());
运行这段代码会输出:
[ 'update', 'end', 'end-soon' ]
如果要订阅另一个事件,例如 myCount.on('some-event', ...)
,则新事件也会添加到数组中。
这个方法不会返回已发布的事件,而是返回订阅的事件的列表。
这个函数可以从 EventEmitter
中删除已订阅的监听器:
const { EventEmitter } = require('events'); const emitter = new EventEmitter(); const f1 = () => { console.log('f1 被触发'); } const f2 = () => { console.log('f2 被触发'); } emitter.on('some-event', f1); emitter.on('some-event', f2); emitter.emit('some-event'); emitter.removeListener('some-event', f1); emitter.emit('some-event');
在第一个事件触发后,由于 f1
和 f2
都处于活动状态,这两个函数都将被执行。之后从 EventEmitter
中删除了 f1
。当再次发出事件时,将会只执行 f2
:
f1 被触发 f2 被触发 f2 被触发
An alias for removeListener()
is off()
. For example, we could have written:
removeListener()
的别名是 off()
。例如可以这样写:
emitter.off('some-event', f1);
该函数用于从 EventEmitter
的所有事件中删除所有侦听器:
const { EventEmitter } = require('events'); const emitter = new EventEmitter(); const f1 = () => { console.log('f1 被触发'); } const f2 = () => { console.log('f2 被触发'); } emitter.on('some-event', f1); emitter.on('some-event', f2); emitter.emit('some-event'); emitter.removeAllListeners(); emitter.emit('some-event');
第一个 emit()
会同时触发 f1
和 f2
,因为它们当时正处于活动状态。删除它们后,emit()
函数将发出事件,但没有侦听器对此作出响应:
f1 被触发 f2 被触发
如果要在 EventEmitter
发出错误,必须用 error
事件名来完成。这是 Node.js 中所有 EventEmitter
对象的标准配置。这个事件必须还要有一个 Error
对象。例如可以像这样发出错误事件:
myEventEmitter.emit('error', new Error('出现了一些错误'));
error
事件的侦听器都应该有一个带有一个参数的回调,用来捕获 Error
对象并处理。如果 EventEmitter
发出了 error
事件,但是没有订阅者订阅 error
事件,那么 Node.js 程序将会抛出这个 Error
。这会导致 Node.js 进程停止运行并退出程序,同时在控制台中显示这个错误的跟踪栈。
例如在 CountDown
类中,countdownTime
参数的值不能小于 2,否则会无法触发 end-soon
事件。在这种情况下应该发出一个 error
事件:
class CountDown extends EventEmitter { constructor(countdownTime) { super(); if (countdownTimer < 2) { this.emit('error', new Error('countdownTimer 的值不能小于2')); } this.countdownTime = countdownTime; this.currentTime = 0; } // ........... }
处理这个错误的方式与其他事件相同:
myCountDown.on('error', (err) => { console.error('发生错误:', err); });
始终对 error
事件进行监听是一种很专业的做法。
Node.js 中许多原生模块扩展了EventEmitter
类,因此它们本身就是事件发射器。
一个典型的例子是 Stream
类。官方文档指出:
流可以是可读的、可写的,或两者均可。所有流都是 EventEmitter
的实例。
先看一下经典的 Stream 用法:
const fs = require('fs'); const writer = fs.createWriteStream('example.txt'); for (let i = 0; i < 100; i++) { writer.write(`hello, #${i}!\n`); } writer.on('finish', () => { console.log('All writes are now complete.'); }); writer.end('This is the end\n');
但是,在写操作和 writer.end()
调用之间,我们添加了一个侦听器。 Stream
在完成后会发出一个 finished
事件。在发生错误时会发出 error
事件,把读取流通过管道传输到写入流时会发出 pipe
事件,从写入流中取消管道传输时,会发出 unpipe
事件。
另一个类是 child_process
类及其 spawn()
方法:
const { spawn } = require('child_process'); const ls = spawn('ls', ['-lh', '/usr']); ls.stdout.on('data', (data) => { console.log(`stdout: ${data}`); }); ls.stderr.on('data', (data) => { console.error(`stderr: ${data}`); }); ls.on('close', (code) => { console.log(`child process exited with code ${code}`); });
当 child_process
写入标准输出管道时,将会触发 stdout
的 data
事件。当输出流遇到错误时,将从 stderr
管道发送 data
事件。
最後に、プロセスが終了すると、close
イベントがトリガーされます。
イベント駆動型アーキテクチャにより、高い凝集性と低い結合性を備えたシステムを作成できます。イベントはアクションの結果を表し、1 つ以上のリスナーを定義してそれに反応できます。
この記事では、EventEmitter
クラスとその機能について詳しく説明します。インスタンス化して直接使用し、その動作をカスタム オブジェクトに拡張します。
最後に、このクラスの重要な機能をいくつか紹介します。
プログラミング関連の知識について詳しくは、プログラミング コースをご覧ください。 !
以上がEventEmitter を使用して Node.js でイベントを処理するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。