EventEmitter3

Introduction

EventEmitter3 is a high-performance EventEmitter. It provides APIs for adding a listener for an event, adding a one-time listener for an event, emitting an event, removing listeners, and obtaining the names and the number of listeners for an event.

How to Install

ohpm install @types/eventemitter3 

For details about the OpenHarmony ohpm environment configuration, see OpenHarmony HAR.

How to Use

After the EventEmitter3 library is installed, import EventEmitter from eventemitter3 and initialize EventEmitter.

import EventEmitter from 'eventemitter3';

let emitter: EventEmitter<string, Object> = new EventEmitter<string, Object>();

Adding a Listener for an Event

Using on()

// Call on() to add a listener for an event named 'event'. When 'event' is emitted, a callback is invoked. In this case, the callback receives no data.
emitter.on('event', () => {
ctx.state = ctx.state + "\r\n" + `Received the event callback.`
});  
// Call on() to add a listener for an event named 'event'. When 'event' is emitted, a callback is invoked. In this case, the callback receives 'data', which is of the string type.
emitter.on('event', (data: string) => {
ctx.state = ctx.state + "\r\n" + `Received the event callback with data of ${data}.`
});

// Call on() to add a listener for an event named 'event'. When 'event' is emitted, a callback is invoked. In this case, the callback receives name and age.
emitter.on('event', (name: string,age: number) => {
The ctx.state = ctx.state + "\r\n" + `Received the event callback, with name of ${data} and age of ${age}'.
});

You can on() to add a listener for an event. After the event is emitted, a callback will be invoked to receive the data passed by the event. The callback supports none or multiple parameters.

Using addListener()

  emitter.addListener('addListener', () => {
      ctx.state = ctx.state + "\r\n" + `Received the addListener event callback.`
  });

 let callback = (data: string) => {
      ctx.state = ctx.state + "\r\n" + `Received the callback event callback with data of ${data}.`
 }
 emitter.addListener('callback', callback);

You can also use addListener() to add a listener for an event. After the event is emitted, a callback will be invoked to receive the data passed by the event. The callback supports none or multiple parameters.

Using once()

emitter.once('single', (data: string) => {
      ctx.state = ctx.state + "\r\n" + `Received the single event callback with data of ${data}.`
    });

You can also use once() to add a listener for an event. The listener will be automatically removed once the callback is invoked.

You can use on(), addListener(), or once() to add a listener for an event. An event can be added with multiple listeners. Each time an event is emitted, the callback registered for the event can receive a notification. The order in which the callbacks receive notifications is as per the order in which the callbacks are registered.

Emitting an Event

emitter.emit("callback")
emitter.emit ('event', "This is original info.");
emitter.emit ('event', 'Tom', 18, "This is original info.");

You can use emit() to emit an event. This API can carry multiple parameters. The first parameter is the event name, and the other parameters are the data carried in the event.

If you use on() or addListener() to add a listener for an event, a callback will be invoked each time the event is emitted.

If you use once(), the callback can be invoked only once after the event is emitted.

emit() must be called after on(), addListener(), or once(). Otherwise, the callback registered for the event cannot receive the event notification.

Removing a Listener from an Event

Using off()

 let listener1 = () => {
 }
 emitter.on('listenNum', listener1);
 emitter.off('listenNum', listener1)

Using removeListener()

For the same event that is added with multiple listeners, all the listeners for the event will be removed if the callback is not specified when removeListener() is used. In the following example, callbacks obj1, obj2, obj3, and obj4 are registered for the same event newListener. The emitter.removeListener('newListener'); API will remove all the listeners for newListener.

let obj1 = () => {}
let obj2 = () => {}
let obj3 = () => {}
let obj4 = () => {}
emitter.on('newListener',obj1 );
emitter.on('newListener', obj2);
emitter.on('newListener', obj3);
emitter.on('newListener', obj4);
emitter.removeListener('newListener');

In the following example, emitter.removeListener('newListener',obj3); will remove only the listener added by emitter.on('newListener', obj3);.

let obj1 = () => {}
let obj2 = () => {}
let obj3 = () => {}
let obj4 = () => {}
emitter.on('newListener',obj1 );
emitter.on('newListener', obj2);
emitter.on('newListener', obj3);
emitter.on('newListener', obj4);
emitter.removeListener('newListener',obj3);

That is the same for off(). If you do not specify the callback in off(), all the listeners added for the same event will be removed.

Using removeAllListeners

Use removeAllListeners to remove all listeners.

emitter.removeAllListeners();

Example

const emitter: EventEmitter<string, Object> = new EventEmitter<string, Object>(); // Initialize EventEmitter.

emitter.on('event', (name: string, age: number) ==> { // Add a listener for an event named 'event'. 
  console.log(`${name} is ${age} years old`);
});
let callback = (data: string) => {   
  console.log(`data is ${data} `);
}
emitter.addListener('callback', callback);// Add a listener for an event named 'callback'.
emitter.emit('event', 'Tom', 18); // Emit the 'event' event.
emitter.listeners('event') // Return all the listeners for the 'event' event.
emitter.listenerCount('event') // Return the number of listeners for the 'event' event.
emitter.eventNames(); // Return the names of all the events observed.
emitter.off('event') // Remove the listeners for the 'event' event.
emitter.removeListener('callback',callback) // Remove the listener for the 'callback' event.
emitter.removeAllListeners() // Remove all event listeners.

Cross-Page Invocation

EntryAbility.ts

import EventEmitter from 'eventemitter3'
import { GlobalContext } from '../pages/GlobalContext'
export default class EntryAbility extends UIAbility {
    
    onWindowStageCreate(windowStage: window.WindowStage) {
      GlobalContext.getContext().setObject(GlobalContext.KEY_CONTEXT, this.context);
      GlobalContext.getContext().setObject(GlobalContext.KEY_CACHE_DIR, this.context.cacheDir);
      GlobalContext.getContext().setObject(GlobalContext.KEY_FILES_DIR, this.context.filesDir);
      const emitter: EventEmitter<string, Object> = new EventEmitter<string, Object>();
      GlobalContext.getContext().setObject(GlobalContext.KEY_EMITTER, emitter);
      windowStage.loadContent('pages/Index', (err, data) => {
    });
  }
}

Index.ets

import { GlobalContext } from './GlobalContext'
        
        Button ('Communication between pages')
        .width('100%')
        .backgroundColor(Color.Blue)
        .fontColor(Color.White)
        .padding(10)
        .margin(20)
        .onClick(() => {
          router.pushUrl({
            url: 'pages/JumpOne'
          }).then(() => {
              // The event must be emitted after the redirection is initiated. Otherwise, the event listener of the next page has not been added and cannot receive the event emitted.
            let emitterInstance: EventEmitter<string, Object> | undefined = GlobalContext.getContext()
              .getObject(GlobalContext.KEY_EMITTER) as EventEmitter<string, Object>;
            if (emitterInstance) {
              emitterInstance.emit ('pageOne','This is the information sent from the home page to page 1.');
            }
          })

        })

JumpOne.ets

import { GlobalContext } from './GlobalContext'
        
  aboutToAppear() {
    const ctx = this
    // When adding a listener during page initialization, use the global EventEmitter object and add the listener before the event is emitted.
    let emitter: EventEmitter<string, Object> | undefined = GlobalContext.getContext()
      .getObject(GlobalContext.KEY_EMITTER) as EventEmitter<string, Object>;
    if (emitter) {
        emitter.on('pageOne', (data: string) => {
          console.log(`componentB Data: ${data}`);
          ctx.message = data
        });
    }
  }

Sequencing Events

import EventEmitter from 'eventemitter3'

@Entry
@Component
struct EventSequencing {
  @State message: string = ''
  @State emitter: EventEmitter<string, Object> | undefined = undefined;

  aboutToAppear() {
    this.emitter = new EventEmitter<string, Object>();
    this.emitter.on('event', (name: string, age: number, message: string) => {}); // Add the same event name in page initialization.
  }

  onPageShow() {
    this.emitter.on('event', (name: string, age: number, message: string) => {}); // Add the same event name when the page is displayed.
  }

  build() {
    Row() {
      Column() {
        Button ('Emit Event')
          .width('100%')
          .height(50)
          .backgroundColor(Color.Blue)
          .fontColor(Color.White)
          .margin(20)
          .onClick(() => {
            this.startSendEvent()
          })
      }
      .width('100%')
    }
    .height('100%')
  }

  startSendEvent() {
    const ctx = this
    // Add an event with the same name for the first time after the button is clicked.
    ctx.emitter.on('event', (name: string, age: number, message: string) => {});
    // Add an event with the same name after the button is clicked the second time.
    ctx.emitter.on('event', (name: string, age: number, message: string) => { });
    ctx.emitter.emit('event', 'Tom', 18, "This is original info.");
  }
}
  

After the event is emitted, the callbacks are invoked in the sequence in which they are added. In some scenarios, you need to sequence the events. For example, to process events in a queue, you need to add the events to EventEmitter3 in sequence.

Available APIs

EventEmitter3

API Parameter Return Value Description
eventNames None Array<EventEmitter.EventNames> Returns the names of all the events observed.
listeners event: T Array<EventEmitter.EventListener<EventTypes, T>> Returns all the listeners of an event.
listenerCount event: EventEmitter.EventNames number Returns the number of listeners for an event.
emit event: T, ...args: EventEmitter.EventArgs<EventTypes, T> boolean Emits an event.
on event: T,
fn: EventEmitter.EventListener<EventTypes, T>,
context?: Context
EventEmitter Listens for an event.
addListener event: T,
fn: EventEmitter.EventListener<EventTypes, T>,
context?: Context
EventEmitter Adds a listener for an event.
once event: T,
fn: EventEmitter.EventListener<EventTypes, T>,
context?: Context
EventEmitter Adds a one-time listener for an event.
removeListener event: T,
fn?: EventEmitter.EventListener<EventTypes, T>,
context?: Context,
once?: boolean
EventEmitter Removes a listener from an event.
off event: T,
fn?: EventEmitter.EventListener<EventTypes, T>,
context?: Context,
once?: boolean
EventEmitter Removes a listener from an event.
removeAllListeners event?: EventEmitter.EventNames EventEmitter Removes all listeners.

For more information, see EventEmitter3 and Unit Test Cases.

Constraints

This project has been verified in the following version:

  • DevEco Studio: NEXT Beta1-5.0.3.806, SDK:API12 Release(5.0.0.66)
  • DevEco Studio: 4.0 Release(4.0.3.513), SDK: API10 Release(4.0.10.10)

Directory Structure

|---- EventEmitter3Demo  
|     |---- entry  # Sample code
			|---- pages  # Application pages, which may vary depending on the test scenario
			   |---- ApiTest.ets          # Full API test cases
                |---- EventSequencing.ets  # Event sequencing example
                |---- FileRead.ets         # Example of file read listening
                |---- GlobalContext.ts     # Global context for singleton mode
                |---- Index.ets            # Homepage
                |---- JumpOne.ets          # Example of jumping to page 1
                |---- JumpTwo.ets          # Example of jumping to page 2
|     |---- README.MD  # Readme                  

How to Contribute

If you find any problem during the use, submit an issue or a PR.

License

This project is licensed under MIT License.