目次
イベントとは何ですか?
以下に別のイベント センダーを作成します。リスナーが3人いるタイマー番組です。最初のリスナーは時間を毎秒更新し、2 番目のリスナーはタイマーが終了するときに起動し、最後のリスナーはタイマーが終了するときに起動します。
eventNames()
removeListener()
removeAllListeners()
错误处理
使用 EventEmitter 的原生模块
概要
ホームページ ウェブフロントエンド jsチュートリアル EventEmitter を使用して Node.js でイベントを処理するにはどうすればよいですか?

EventEmitter を使用して Node.js でイベントを処理するにはどうすればよいですか?

Nov 02, 2020 pm 05:46 PM
node.js フロントエンド

EventEmitter を使用して Node.js でイベントを処理するにはどうすればよいですか?

このチュートリアルでは、Node.js のネイティブ EvenEmitter クラスについて学びます。コースを完了すると、イベント、EvenEmitter の使用方法、およびプログラムでのイベントの利用方法を理解できるようになります。さらに、EventEmitter クラスが他のローカル モジュールからどのように拡張されるのかを学び、いくつかの例を通じてその背後にある原則を理解します。

推奨チュートリアル: node js チュートリアル

つまり、この記事では EventEmitter クラスに関するすべてを説明します。

イベントとは何ですか?

イベント駆動型のアーキテクチャは現在非常に一般的であり、イベント駆動型のプログラムはさまざまなイベントを生成、検出し、それに応答できます。

Node.js のコア部分はイベント駆動型であり、ファイル システム (fs) や stream などの多くのモジュール自体が EventEmitter # を使用します。 ## によって書かれた。

イベント駆動型プログラミングでは、

Event (event) は、ユーザーの操作やセンサーのタイミング出力など、1 つ以上のアクションの結果です。

イベント駆動型プログラムは、パブリッシャーがイベントをトリガーし、サブスクライバーがイベントをリッスンして適切なアクションを実行する、パブリッシュ/サブスクライブ モデルとして考えることができます。

たとえば、ユーザーが画像をアップロードできるサーバーがあるとします。イベント駆動型プログラミングでは、画像のアップロードなどのアクションによってイベントが発行され、それを利用するために 1 ~ n 人のサブスクライバーも発生します。

アップロード イベントがトリガーされた後、サブスクライバーは、サイトの管理者に電子メールを送信することで、サイトの管理者に通知し、対応することができます。別のサブスクライバーは、アクションに関する情報を収集し、データベースに保存することができます。

これらのイベントは通常、互いに独立していますが、相互に依存する場合もあります。

イベントエミッターとは何ですか?

EventEmitter クラスは、events モジュールにある Node.js の組み込みクラスです。ドキュメントの説明によると:

Node.js コア API のほとんどは、慣用的な非同期イベント駆動型アーキテクチャに基づいて実装されており、特定の種類のオブジェクト (「エミッター」と呼ばれる) が名前付きイベントを発行します。
Function オブジェクト (「リスナー」) への呼び出しが発生します。"
このクラスは、パブリッシュ/サブスクライブ モデルとしてある程度記述することができます。補助ツールの実装は、イベント エミッター (

Create EventEmitters

そうは言っても、

EventEmitter を作成する方がより現実的です。これを行うには、クラス自体のインスタンスを作成するか、カスタム クラスを通じて実装してから、クラスのインスタンスを作成します。

Create

EventEmitter Object

簡単な例から始めます。プログラムの実行時間情報を含むイベントを毎秒発行する

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> 次に、

EventEmitter

: <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()

2 番目関数のパラメータは、イベントによって発行された追加データを受け入れることができるコールバックです。

コードを実行すると、次の出力が出力されます:

从发布者收到的消息:
程序已经运行了 1 秒
从发布者收到的消息:
程序已经运行了 2 秒
从发布者收到的消息:
程序已经运行了 3 秒
...
ログイン後にコピー
イベントが初めてトリガーされたときのみ特定の操作を実行する必要がある場合は、

once()

メソッドを使用してサブスクライブすることもできます:

timerEventEmitter.once('update', (time) => {
    console.log('从发布者收到的消息:');
    console.log(`程序已经运行了 ${time} 秒`);
});
ログイン後にコピー
このコードを実行すると、出力:
从发布者收到的消息:
程序已经运行了 1 秒
ログイン後にコピー

EventEmitter

複数のリスナーを使用する場合

以下に別のイベント センダーを作成します。リスナーが3人いるタイマー番組です。最初のリスナーは時間を毎秒更新し、2 番目のリスナーはタイマーが終了するときに起動し、最後のリスナーはタイマーが終了するときに起動します。

update
    : 毎秒一度トリガー
  • #end: カウントダウン終了時にトリガー
  • #end-soon: カウントダウン終了の 2 秒前にトリガー
  • 最初に、このイベント エミッターを作成する関数を作成します: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">const countDown = (countdownTime) =&gt; {     const eventEmitter = new EventEmitter();     let currentTime = 0;     // 每秒触发一次 update 事件     const timer = setInterval(() =&gt; {         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

    接下来通过扩展 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秒后结束');
    });
    ログイン後にコピー

    EventEmitter 的主要函数

    eventNames()

    此函数将以数组形式返回所有活动的侦听器名称:

    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', ...),则新事件也会添加到数组中。

    这个方法不会返回已发布的事件,而是返回订阅的事件的列表。

    removeListener()

    这个函数可以从 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');
    ログイン後にコピー

    在第一个事件触发后,由于 f1f2 都处于活动状态,这两个函数都将被执行。之后从 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);
    ログイン後にコピー

    removeAllListeners()

    该函数用于从 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() 会同时触发 f1f2,因为它们当时正处于活动状态。删除它们后,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(&#39;error&#39;, new Error(&#39;countdownTimer 的值不能小于2&#39;));
            }
    
            this.countdownTime = countdownTime;
            this.currentTime = 0;
        }
    
        // ...........
    }
    ログイン後にコピー

    处理这个错误的方式与其他事件相同:

    myCountDown.on(&#39;error&#39;, (err) => {
        console.error('发生错误:', err);
    });
    ログイン後にコピー

    始终对 error 事件进行监听是一种很专业的做法。

    使用 EventEmitter 的原生模块

    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(&#39;finish&#39;, () => {
      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 写入标准输出管道时,将会触发  stdoutdata 事件。当输出流遇到错误时,将从 stderr 管道发送 data 事件。

    最後に、プロセスが終了すると、close イベントがトリガーされます。

    概要

    イベント駆動型アーキテクチャにより、高い凝集性と低い結合性を備えたシステムを作成できます。イベントはアクションの結果を表し、1 つ以上のリスナーを定義してそれに反応できます。

    この記事では、EventEmitter クラスとその機能について詳しく説明します。インスタンス化して直接使用し、その動作をカスタム オブジェクトに拡張します。

    最後に、このクラスの重要な機能をいくつか紹介します。

    プログラミング関連の知識について詳しくは、プログラミング コースをご覧ください。 !

以上がEventEmitter を使用して Node.js でイベントを処理するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

PHP と Vue: フロントエンド開発ツールの完璧な組み合わせ PHP と Vue: フロントエンド開発ツールの完璧な組み合わせ Mar 16, 2024 pm 12:09 PM

PHP と Vue: フロントエンド開発ツールの完璧な組み合わせ 今日のインターネットの急速な発展の時代において、フロントエンド開発はますます重要になっています。 Web サイトやアプリケーションのエクスペリエンスに対するユーザーの要求がますます高まっているため、フロントエンド開発者は、より効率的で柔軟なツールを使用して、応答性の高いインタラクティブなインターフェイスを作成する必要があります。フロントエンド開発の分野における 2 つの重要なテクノロジーである PHP と Vue.js は、組み合わせることで完璧なツールと見なされます。この記事では、PHP と Vue の組み合わせと、読者がこれら 2 つをよりよく理解し、適用できるようにするための詳細なコード例について説明します。

フロントエンド開発に Go 言語を使用するにはどうすればよいですか? フロントエンド開発に Go 言語を使用するにはどうすればよいですか? Jun 10, 2023 pm 05:00 PM

インターネット技術の発展に伴い、フロントエンド開発の重要性がますます高まっています。特にモバイル デバイスの人気により、効率的で安定しており、安全で保守が容易なフロントエンド開発テクノロジーが必要です。 Go 言語は、急速に発展しているプログラミング言語として、ますます多くの開発者によって使用されています。では、フロントエンド開発に Go 言語を使用することは可能でしょうか?次に、この記事ではフロントエンド開発にGo言語を使用する方法を詳しく説明します。まずはフロントエンド開発にGo言語が使われる理由を見てみましょう。多くの人は Go 言語は

フロントエンドの面接官からよく聞かれる質問 フロントエンドの面接官からよく聞かれる質問 Mar 19, 2024 pm 02:24 PM

フロントエンド開発のインタビューでは、HTML/CSS の基本、JavaScript の基本、フレームワークとライブラリ、プロジェクトの経験、アルゴリズムとデータ構造、パフォーマンスの最適化、クロスドメイン リクエスト、フロントエンド エンジニアリング、デザインパターン、新しいテクノロジーとトレンド。面接官の質問は、候補者の技術スキル、プロジェクトの経験、業界のトレンドの理解を評価するように設計されています。したがって、候補者はこれらの分野で自分の能力と専門知識を証明するために十分な準備をしておく必要があります。

Django はフロントエンドですか、バックエンドですか?それをチェックしてください! Django はフロントエンドですか、バックエンドですか?それをチェックしてください! Jan 19, 2024 am 08:37 AM

Django は、迅速な開発とクリーンなメソッドを重視した Python で書かれた Web アプリケーション フレームワークです。 Django は Web フレームワークですが、Django がフロントエンドなのかバックエンドなのかという質問に答えるには、フロントエンドとバックエンドの概念を深く理解する必要があります。フロントエンドはユーザーが直接対話するインターフェイスを指し、バックエンドはサーバー側プログラムを指し、HTTP プロトコルを通じてデータと対話します。フロントエンドとバックエンドが分離されている場合、フロントエンドとバックエンドのプログラムをそれぞれ独立して開発して、ビジネス ロジックとインタラクティブ効果、およびデータ交換を実装できます。

golang はフロントエンドとして使用できますか? golang はフロントエンドとして使用できますか? Jun 06, 2023 am 09:19 AM

Golang はフロントエンドとして使用できます。Golang は、フロントエンド アプリケーションなど、さまざまなタイプのアプリケーションの開発に使用できる非常に多用途なプログラミング言語です。Golang を使用してフロントエンドを作成することで、 JavaScript などの言語によって引き起こされる一連の問題、たとえば、型安全性の低さ、パフォーマンスの低下、コードの保守の困難などの問題です。

C# 開発経験の共有: フロントエンドとバックエンドの共同開発スキル C# 開発経験の共有: フロントエンドとバックエンドの共同開発スキル Nov 23, 2023 am 10:13 AM

C# 開発者としての私たちの開発作業には、通常、フロントエンドとバックエンドの開発が含まれますが、テクノロジーが発展し、プロジェクトが複雑になるにつれて、フロントエンドとバックエンドの共同開発はますます重要かつ複雑になってきています。この記事では、C# 開発者が開発作業をより効率的に完了できるようにする、フロントエンドとバックエンドの共同開発テクニックをいくつか紹介します。インターフェイスの仕様を決定した後、フロントエンドとバックエンドの共同開発は API インターフェイスの相互作用から切り離せません。フロントエンドとバックエンドの共同開発をスムーズに進めるためには、適切なインターフェース仕様を定義することが最も重要です。インターフェイスの仕様にはインターフェイスの名前が含まれます

Go 言語のフロントエンド テクノロジーの探求: フロントエンド開発の新しいビジョン Go 言語のフロントエンド テクノロジーの探求: フロントエンド開発の新しいビジョン Mar 28, 2024 pm 01:06 PM

Go 言語は、高速で効率的なプログラミング言語として、バックエンド開発の分野で広く普及しています。ただし、Go 言語をフロントエンド開発と結びつける人はほとんどいません。実際、フロントエンド開発に Go 言語を使用すると、効率が向上するだけでなく、開発者に新たな視野をもたらすことができます。この記事では、フロントエンド開発に Go 言語を使用する可能性を探り、読者がこの分野をよりよく理解できるように具体的なコード例を示します。従来のフロントエンド開発では、ユーザー インターフェイスの構築に JavaScript、HTML、CSS がよく使用されます。

Golang とフロントエンド テクノロジーの組み合わせ: Golang がフロントエンド分野でどのような役割を果たすかを探る Golang とフロントエンド テクノロジーの組み合わせ: Golang がフロントエンド分野でどのような役割を果たすかを探る Mar 19, 2024 pm 06:15 PM

Golang とフロントエンド テクノロジーの組み合わせ: Golang がフロントエンド分野でどのような役割を果たしているかを調べるには、具体的なコード例が必要です。インターネットとモバイル アプリケーションの急速な発展に伴い、フロントエンド テクノロジーの重要性がますます高まっています。この分野では、強力なバックエンド プログラミング言語としての Golang も重要な役割を果たします。この記事では、Golang がどのようにフロントエンド テクノロジーと組み合わされるかを検討し、具体的なコード例を通じてフロントエンド分野での可能性を実証します。フロントエンド分野における Golang の役割は、効率的で簡潔かつ学びやすいものとしてです。

See all articles