So I ran into some Javascript weirdness if i write a function like this my passed callback works fine
messageHandler(callback) {
this.ws.onmessage = (data) => {
callback(data.data);
};
}
If you write like this
messageHandler(callback) {
this.ws.on('message', (data) => {
callback(data);
});
}
It mutates the callback into a message event I can't seem to figure out why but I'd like to understand this behavior if anyone can explain. Thanks in Advance.
I think the question omits crucial information but based on the code examples, I think you're using https://github.com/websockets/ws implementation, correct?
If so, then .ws.on('message', ... refers to Event Emitter listener. The params passed to your handler is the message or stream or whatever data object the emitter emits.
.ws.onmessage refers to the browser's Websocket API - so the parameter passed there is a MessageEvent. As you can see from the spec, data is a property on MessageEvent class which explains why you have to refer with 1 level of indirection as data.data.
Perhaps it'd be less confusing if you call your parameter event instead of data in the first example:
this.ws.onmessage = (event) => {
callback(event.data);
};
You can also view this as server side events vs. client side events - your first example is a client side event whereas the second example is a server side event. Client side events conform to Websockets API whereas server side events, in NodeJS world, typically use event emitters.
Related
Comming from a c# background, I just want to create an event in a certain point of my code, soas to be dispatched elsewere, meaning that if in some part of the code there has been a subscription, this delegate function is called.
So I tried to do:
function myFunction() {
console.log("delegated call achieved!");
}
const myEvent = new Event('onMyConditionIsMet', myFunction, false);
//at this point the program the subscription takes place
function whatever1() {
//...not meaningfull code
myEvent.addEventListener('onMyConditionIsMet');
//myEvent += myFunction; c# way subscription in case it makes sense
}
//at this point in the program, event subscription is checked and
//delegate func run in case there has been a subscription
function whatever2() {
//...not meaningfull code
myEvent?.invoke(); // ?.invoke(); would be the c# way to do it.
}
All the examples I found are related to DOM events, but my case would be for events I create myself, think these are called synthetic events.
Another assumption I make in this question is that there would be no arguments in the delegate call function, so, just to be clear with the naming, it would be a delegate with no arguments. Just pointing this because in c# events are just delegate funcs with no arguments, so a specific type of delegate. Not sure if this works the same way in Javscript.
What would be the approach to do this? (Meaning creating a simple event instance, subscribing, and executing the delegated code if there is any subscription)?
I think the functionality you are looking for can be best obtained by using OOP/Classes.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#prototype_methods
Edit: see this also - "event" is deprecated, what should be used instead?
I have little nooby question about event emitter but it is really important for may program logic.
I am using some external library that fires events I am listening. Lets say it fires 2 events : 'data' and 'error'. Lets say that lib will always call data before error, something like this:
emit('data', 'some data');
emit('error', 'some error');
Question is: can I be 100% sure that data event will always come before error event in my listen methods?:
lib.on('data', function(data) {
// is this always first
});
lib.on('error', function(error) {
// or maybe this
});
Thanks,
Ivan
The EventEmitter emit function is a synchronous blocking function. And hence, like any other blocking function, it is guaranteed to execute in the exact order it is called in.
I've written happily a node.js server, which uses socket.io to communicate with the client.
this all works well.
the socket.on('connection'...) handler got a bit big, which made me think of an alternative way to organize my code and add the handlers in a generator function like this:
sessionSockets.on('connection', function (err, socket, session) {
control.generator.apply(socket, [session]);
}
the generator takes an object that contains the socket events and their respective handler function:
var config = {
//handler for event 'a'
a: function(data){
console.log('a');
},
//handler for event 'b'
b: function(data){
console.log('b');
}
};
function generator(session){
//set up socket.io handlers as per config
for(var method in config){
console.log('CONTROL: adding handler for '+method);
//'this' is the socket, generator is called in this way
this.on(method, function(data){
console.log('CONTROL: received '+method);
config[method].apply(this, data);
});
}
};
I was hoping that this would add the socket event handlers to the socket, which it kind of does, but when any event comes in, it always calls the latest one added, in this case always the b-function.
Anyone any clues what i am doing wrong here?
The problem appears because by that time this.on callback triggers (let's say in a few seconds after you bind it), the for loop is finished and method variable becomes the last value.
To fix that you may use some JavaScript magic:
//set up socket.io handlers as per config
var socket = this;
for(var method in config){
console.log('CONTROL: adding handler for '+method);
(function(realMethod) {
socket.on(realMethod, function(data){
console.log('CONTROL: received '+realMethod);
config[realMethod].apply(this, data);
});
})(method); //declare function and call it immediately (passing the current method)
}
This "magic" is hard to understand when you first see it, but when you get it, the things become clear :)
I have a global event manager, allowing you to listen with lambdas to string event names.
// somewhere in the ModuleScript class
Event->Listen("WindowResize", [=]{
// ...
});
Now, I want to register to events from JavaScript, too. Therefore, I wrote this callback.
v8::Handle<v8::Value> ModuleScript::jsOn(const v8::Arguments& args)
{
// get pointer to class since we're in a static method
ModuleScript *module = (ModuleScript*)HelperScript::Unwrap(args.Data());
// get event name we want to register to from arguments
if(args.Length() < 1 || !args[0]->IsString())
return v8::Undefined();
string name = *v8::String::Utf8Value(args[0]);
// get callback function from arguments
if(args.Length() < 2 || !args[1]->IsFunction())
return v8::Undefined();
v8::Handle<v8::Function> callback =
v8::Local<v8::Function>::Cast(args[1]->ToObject());
// register event on global event manager
module->Event->Listen(name, [=]{
// create persistent handle so that function stays valid
// maybe this doesn't work, I don't know
v8::Persistent<v8::Function> function =
v8::Persistent<v8::Function>::New(args.GetIsolate(), callback);
// execute callback function
// causes the access violation
function->Call(function, 0, NULL);
});
return v8::Undefined();
}
When the event is triggered, the application crashes with a access violation. My thoughts are that either the function object isn't valid at this time anymore, or it is a JavaScript scope issue. But I couldn't figure it out.
What causes the access violation and how to overcome it?
I believe there are several potential issues here.
First, you're not using a persistent handle to hold the JavaScript function after ModuleScript::jsOn() terminates. By the time your event handler is invoked, the function might be gone. Consider making callback a persistent handle.
Second, your event handler needs to enter an appropriate V8 context before calling the JavaScript function. Depending on your architecture, explicitly locking and entering the V8 isolate may be required as well.
Third (and this may not be an issue in your specific scenario), you need to manage the lifetime of the V8 isolate. If your event manager fires events on background threads, you have to make sure your event handler somehow prevents the isolate from being disposed from another thread. Unfortunately this is one area where the V8 API doesn't provide much help.
Fourth, to prevent a leak, your event handler should dispose the persistent function handle after invoking the function.
Good luck!
In socket.io, will using "on" twice replace the older registration or will the event fire both listeners? Is it a generally consistent behavior with javascript "on" methods in general? And is there a reason there is no socket.io documentation for this?
var socket = io.connect("host:port")
socket.on('data', function(data) {
console.log('listener1');
}
socket.on('data', function(data) {
console.log('listener2');
}
JavaScript has no on method. Libraries just implement this as part of an Event Emitter/Pub-Sub pattern, where code "listens" from other code.
And no, it will not replace the existing registrations. They get added into a "queue". Think of it as this: It's not only one piece of code that listens for data to arrive. There could be hundreds of lines listening for that same data.