I would like to use an event in node.js to execute some code; my question is, what is the scope of the invoked event code? Specifically, does it share the scope of the event invoker, or is it "isolated"? I know that I can pass parameters to the code invoked on the event to achieve a similar effect, but ideally I'd like to have the invoking scope available.
The event is tied to the scope of the invoker. i.e. an EventEmitter exported from a module, can only be used to listen for events emitted from that same EventEmitter.
Nodejs EventEmitter - Define scope for listener function
When you emit an event, you put it into a queue to be processed later by the node event system. Any variables from the scope where the event is emitted must be passed to emit as arguments. When node takes that event and triggers all bound callbacks, that happens under both a distinct "clean" scope and a distinct "clean" stack. (Side note, this is why stack traces in node can be a nuisance for debugging).
var events = require('events');
var myEmitter = new events.EventEmitter();
function closure1(word, number) {
function closure2(animal, vegetable) {
myEmitter.emit('hey', word, number, animal, vegetable, 43);
}
closure2("horse", "carrot");
}
myEmitter.on('hey', function (word, number, animal, vegetable, anotherNumber) {
console.log('hey event fired with', word, number, animal, vegetable, anotherNumber);
});
closure1("table", 42);
When you run that, it will print "hey event fired with table 42 horse carrot 43".
see the node.js docs on emitter.emit(event, [arg1], [arg2], [...]
Related
When using the EventEmitter class in Node.js what is the best practice way to chain together different events?
Let's say I have multiple events, and I want to emit/trigger event 'B' but only inside the listener of some other initial event, 'A'. I was able to do something like that below, I'm just wondering if it is correct / memory-efficient to reference the eventEmitter instance in its own event listeners?
import {EventEmitter} from 'events';
const eventEmitter = new EventEmitter();
const eventTypes = ['txRequestReceived', 'txRequestComplete'];
eventEmitter.on('txRequestReceived', (params)=>{
let {chainID, address} = params;
console.log(`txRequestReceived event: ${chainID} -- ${address}`);
eventEmitter.emit('txRequestComplete', {"chainID": chainID, "address": address});
});
eventEmitter.on('txRequestComplete', (params)=>{
let {chainID, address} = params;
console.log(`txRequestComplete event: ${chainID} -- ${address}`);
});
This does work, and I'm able to pass around an event payload with the listener parameters. I'm wondering if there are memory / scope issues with it? If I were to write a class and extend the EventEmitter class, would I just use the 'this' keyword to access .emit() and .on() behaviour?
I was able to find this "answer" (which I will accept). The pattern I used works, but there are caveats surrounding the fact that EventEmitter is synchronous and how closures with the handlers may handle memory.
https://www.codementor.io/#simenli/demystifying-asynchronous-programming-part-2-node-js-eventemitter-7r51ivby4
So I've attached two events if someone screams, they are called synchronously, why so?
const events = require('events');
const eventEmitter = new events.EventEmitter();
eventEmitter.on('scream', function() {
console.log("Screaming");
});
eventEmitter.on('scream', function(name) {
console.log(name+" is screaming");
});
eventEmitter.emit('scream', 'Bob');
O/P:
Screaming
Bob is screaming
Because in nodejs, The event loop is single threaded and pick one event at a time and treat those events independently.
In your case, there are two event handler with the same name, so when event loop gets the eventEmitter.emit('scream', 'Bob') it sends the particular event handler.
When first event handler done with it, Now it goes to the second handler because with the same name.
It follow the FIFO but if you use emitter.prependListener(eventName, listener) then it will be executed first the FIFO.
You should know, if you want to call only one time then you should use eventEmitter.once('scream') It will be called only one time.
eventEmitter.once('scream', function() {
console.log("Screaming");
});
eventEmitter.emit('scream', 'Bob');
eventEmitter.emit('scream', 'Bob');
eventEmitter.emit('scream', 'Bob');
Output: Screaming // Only one time.
Because the Event loop fetches events from Event Queue and sends them to call stack one by one.
And Event Queue is FIFO (First-In-First-Out)
I would like to get the data from a client (AR.Drone 2.0) just once and them store it in a variable to be printed. I have used:
client.on('navdata', console.log);
however, when I execute this command data is printed more than once and I have to stop the script to stop this process. How can I get the data just once and store it in a variable.
Client object inherits EventEmitter, so you should be able to use once() to listen for navdata event only once. To store the emitted value to a variable you can do something like:
var _navData;
// ...
client.once('navdata', function (navData) {
_navData = navData;
});
Update
Regarding to your comment, I suggest you to declare a function that gets a navdata object as an argument and pass that function to client.once():
var doSomethingWithNavData = function doSomethingWithNavData(navData) {
console.log(navData);
// do what ever you want to do with navData...
}
client.once('navdata', doSomethingWithNavData);
There are two EventEmitter methods for adding listeners: .on() and .once().
.on() actively listens and catches events until .removeListener() or .removeAllListeners() are called to remove the listener.
.once() listens for the next event and removes itself automatically (effectively running once), unless .removeListener() or .removeAllListeners() are called to remove it before it does.
Can I have access to the name of an event from within the callback which is executed when the event is triggered?
Consider the following example, where I have the same callback (handleEvent)for two differenct events. Now I want to add a conditional statement in the callback based on the event that triggered its execution. Is this possible?
obj.on('start', handleEvent);
obj.on('stop', handleEvent);
function handleEvent() {
// how can I check here if the event that triggers the execution of handleEvent is 'start' or 'stop'
}
What I do at the moment is to pass the event two times with 'emit' - which seems to be working fine, but i don't like to write it twice:
obj.emit('start', 'start', handleEvent);
Try EventEmitter2:
var EventEmitter = require('eventemitter2').EventEmitter2
var emitter = new EventEmitter
emitter.on('test', onEvent)
emitter.emit('test')
function onEvent() {
console.log(this.event)
}
You can do:
obj.on('start', handleEvent.bind({ event: 'start' }));
obj.on('stop', handleEvent.bind({ event: 'stop' }));
function handleEvent() {
if(this.event == 'start') { ///
}
Which is the best approach for listening/launching events in node.js?
I've been testing event launching and listening in node.js by extending the model with EventEmitter and I'm wondering if it has sense this approach since the events are only listened when there is a instance of the model.
How can be achieved that events will be listened while the node app is alive??
Example for extending the model using eventEmitter.
// myModel.js
var util = require('util');
var events2 = require('events').EventEmitter;
var MyModel = function() {
events2.call(this);
// Create a event listener
this.on('myEvent', function(value) {
console.log('hi!');
});
};
MyModel.prototype.dummyFunction = function(params) {
// just a dummy function.
}
util.inherits(MyModel, events2);
module.exports = MyModel;
EDIT: A more clear question about this would be: how to keep a permanent process that listens the events during the app execution and it has a global scope (something like a running event manager that listens events produced in the app).
Would be a solution to require the file myModel.js in app.js? How this kind of things are solved in node.js?
I'm not entirely sure what you mean about events only being active when there is an instance of a model since without something to listen and react to them, events cannot occur.
Having said that, it is certainly reasonable to:
util.inherits(global,EventEmitter)
global.on('myEvent',function(){
/* do something useful */
});
which would allow you to:
global.emit('myEvent')
or even:
var ee=new EventEmitter();
ee.on('myEvent',...)
As for how to properly use EventEmitter: it's defined as
function EventEmitter() {}
which does not provide for initialization, so it should be sufficient to:
var Thing=function(){};
util.inherits(Thing,EventEmitter);
which will extend instances of Thing with:
setMaxListeners(num)
emit(type,...)
addListener(type,listener) -- aliased as on()
once(type,listener)
removeListener(type,listener)
removeAllListeners()
listeners(type)
The only possible "gotcha" is that EventEmitter adds its own _events object property to any extended object (this) which suggests you should not name any of your own object properties with the same name without unexpected behavior.