はじめに
この記事ではeventEmitterとeventEmitterに関わるデザインパターンについて紹介しています。
evenEmitterをマスターすることで、よりプロのプログラマー(略してプロプロ)になれると思います。
eventemitterとは
まずイベントエミッターとはなにか説明します。
これ、独自にイベントを作成し、指定したタイミングに関数を発火することができます
イベント駆動開発でよく用いられます。
イメージで言うと、フロントエンドでいうと、ボタンを押したときにonpushに登録された関数が発火しますよね。それです!
eventemitterを用いると、自作でイベントを作って、好きなタイミングで発火することができるようになります。
Node.jsではeventemitterがストリームの裏側で作られ、実行されています。
EventEmitterの実行例
const EventEmitter = require("events")
const eventEmitter = new EventEmitter()
const bakuhatsu=() => { console.log("ドッカーーーン") }
eventEmitter.on("爆発",bakuhatsu)
eventEmitter.once("爆発", () => {
console.log("一回だけドッカーーーン")
})
eventEmitter.emit("爆発")
//ドッカーーーン
//一回だけドッカーーーン
eventEmitter.emit("爆発")
//ドッカーーーン
console.log("爆発解除")
eventEmitter.off("爆発",bakuhatsu)
eventEmitter.emit("爆発")
//(何もなし)
EventEmitter の主要なインスタンスメソッド
最初に簡単に用法をまとめておきます。
-
on(イベント名、関数名)
でイベントを登録し、 -
emit(イベント名)
でイベントに指定した関数を実行! -
off(イベント,関数名)
でイベントに登録した関数の削除
on(event,listener)
指定したイベントに新しいリスナを登録します。
(第一引数に文字列 イベントの名前(任意)
第二引数にコールバック関数 第一引数に登録したイベントが呼ばれたときに発火する)
eventEmitter.on("爆発",()=>{console.log("ドッカーーーン")})
once(event,listener)
指定したイベントに新しいリスナを登録します。
(第一引数に文字列 イベントの名前(任意)
第二引数にコールバック関数 第一引数に登録したイベントが呼ばれたときに発火する)
これはon()メソッドと同様です。
このリスナは、イベントが一回発行されるとリスナが削除されます。なので、そのイベントの最初の一回しか第二引数に登録したコールバック関数が実行されません。
eventEmitter.once("爆発",()=>{console.log("一回だけドッカーーーン")})
off(event,listener)
on()メソッドで登録したイベントの特定のリスナを削除します。
(第一引数に文字列 イベントの名前(任意)
第二引数にコールバック関数 on()メソッドで登録した第二引数)
eventEmitter.off("爆発",()=>{console.log("ドッカーーーン")})
emit(event,[...args])
on()やonce()メソッドで追加したイベントを発火します。
(第一引数に文字列 イベントの名前(任意)
第二引数には引数 on()やonce()で登録したコールバック関数に引数が必要な場合のみ使用する)
eventEmitter.emit("爆発") //今回は引数なし
使い方は、以上です
ここからは、eventemitterを利用するデザインパターンについて説明していきます。
まずかんたんにデザインパターンについて説明しておきます。
デザインパターンとは
オブジェクト指向言語で使われる設計パターンのことです。オブジェクト指向では再利用性の高いクラスが必須です。
ではどのような方向性で設計していけばよいのか。。。。
それを示してくれるのがデザインパターンです。
代表的なデザインパターンは23種類あります。(今回は詳しく説明しない)
ここではeventemitterで用いられるObserverパターンについて解説していきます。
Observerパターンについて
ObserverパターンはNode.js以外でもよく用いられる代表的なデザインパターンです。英語のObserverとは、観察者や監視役という意味があります。
このパターンでは、監視対象に対して発生した何らかのイベントが、監視役(Observer)に逐一通知されます。
監視役(Observer)はあらかじめ監視対象に対して監視を行うための登録処理を行い、監視対象はイベントの発生タイミングで登録済みの監視役(Observer)に対して通知処理を実行します。
それぞれのSubjectには複数のObserverを登録できます。
簡単な例を上げて説明します。
中学校を想定します。ここでは、一人の生徒が監視対象です。先生は一人の生徒「たかひろ」くんに対してそれぞれの処理を仕込みます。
それぞれの先生は、自分の専門の処理を「たかひろ」くんに仕込みます。
そして「たかひろ」くんは登録された処理に従って、
数学の勉強がわからないときは数学の先生に、
野球の打撃の成績が悪いときは、筋肉の先生に、(「たかひろ」くんは野球部)
熱があって、吐き気もするときは、保健室の先生に、
通知を出します。
ここまでがObserverパターンです。
先生が生徒に処理を仕込み、生徒が通知を出すところまででひとくくりです。
ここでこの例に従ってeventemitterのコードを書いてみます。
const EventEmitter = require("events")
const eventEmitter = new EventEmitter()
const helpme=(teacher)=>{
console.log(teacher+"、助けてください")
}
eventEmitter.on("数学がわからない", helpme)
eventEmitter.on("最近打率が悪い", helpme)
eventEmitter.on("体調が悪い", helpme)
// 先生(Observer)によってイベントが仕込まれる
class takahiro {
static suugaku_nervous() {
eventEmitter.emit("数学がわからない","数学得意な先生")
}
static sports_nervous() {
eventEmitter.emit("最近打率が悪い","筋肉ムキムキな先生")
}
static condition_nervous() {
eventEmitter.emit("体調が悪い","保健室の先生")
}
}
//「たかひろ」くんが先生にイベントを通知する
takahiro.suugaku_nervous()
//***実行結果***
//数学得意な先生、助けて!
デザインパターンとeventemitterの話はここまでです。
実際のコード
最後に実際に使われているコードの紹介をしておきます。
const http = require("http")
var fs = require("fs")
//serverのeventEmitterを作成
const server = http.createServer()
//requestというイベントに関数を仕込む
//serverにアクセスがあったときに発火する
server.on("request", (req, res) => {
fs.readFile("./helloWorld.html", "utf-8", function (error, data) {
res.writeHead(200, { "Content-Type": "text/html" })
res.write("requestに登録されたイベント発火")
res.write(data)
res.end()
})
})
//listeningというイベントに関数を仕込む
//これはserver.listen(8000)したときに発火する
server.on("listening", (res, req) => {})
//errorというイベントに関数を仕込む
//エラーが起こったときに発火する
server.on("error", err =>{
console.error(err);
})
//closeというイベントに関数を仕込む
//これはserver.close()したときに発火する(ここではserver.close()はこめんとあうとした)
server.on("close", () => {})
server.listen(8000)
// server.close()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Hello,Earth! And,Hello universe!</h1>
</body>
</html>
localhost:8000にアクセスした結果
何気なくhttpモジュールで使っていた関数にもeventEmitterが仕込まれていました。自分が使っている関数や処理がeventEmitterのものかどうか見極める事ができれば、プログラミングのレベルもぐんぐん上がっていくと思いますl
最後に
Streamの記事を書くつもりがいつマニカeventEmitter の記事を書いていました。
次回はStreamの記事を書きます!!
おいらの記事を最後まで見てくれてありがとうございました。