In one place we use eventEmitter to generate events. Actually it's the very common way.
eventEmitter.emit('started', data, date);
In the other place we try to catch it. Everything is pretty clear when using arrow functions. 'data' and 'date' are passed to the function as arguments
someInstanse.event.on('started', (data, date) => {
//crazy stuff here
})
But how this notaion in fact works? We determine 3 args with emitter and now we really have only event string and a function instead
someInstance.event.on('started', function(data, date) {
});
I suppose that before adding arrow functions it was the only way to call anonymous functions
This is the typical publish/subscribe design pattern. And it is really determined by how the emit and how subscribers respond to the event are implemented under the hood.
Basically, in the publish function, you want to call every subscriber(on) functions, provided with the information with publish(emit). Below is just some pseudo-code.
function publish(type, ...args) {
// for each of the subscribers of that type
for (let i = 0; i < pubsub[type].length; i++) {
// you could do (this provides the listener with type)
subscribers[i](type, ...args)
// or you could do (the subscriber doesn't know the type)
subscriber[i](...args)
}
}
I wrote a minified pub/sub pattern in github, if you want to take a look. I think it's extremely helpful to help you understand this issue.
https://github.com/thomasyimgit/pubsub/blob/master/index.js
Related
Let me start by saying this is more of a curiosity question because, as you will see, I was able to achieve the desired functionality.
However, given that javascript is a super flexible language, I would like to see what other devs might think about this problem:
I have an instance of a class which is returned from a vendor function:
const connection = vendorDatabaseLib.createConnection();
Now, I would like to create a decorator which will add functionality to the connection class, for example, reconnection logic.
Lets call it PersistentConnection. Apart from my added custom functions I would like an instance of PersistentConnection to forward all function calls to the original Connection instance. And in some functions override the behaviour.
I could of course implement all Connection's functions explicitly and forward them to the inner object but there might be lots of these functions, so I quickly discarded this idea.
So here are my ideas of how to achieve this:
Monkey patching 🐒, Instead of a decorator I can create a PersistentConnection class which inherits from the vendor Connection and then patch the vendor vendorDatabaseLib.createConnection function to return PersistentConnection with all my desired added functionality. Tempting, but bad.
Create a decorator which iterates over the Connection functions and creates forwards dynamically, something like:
class PersistentConnection{
constructor(connection){
this._connection = connection;
// Iterate through all functions
for (prop in this._connection){
if(typeof(this._connection[prop]) === 'function'){
// Create functions dynamically for each forward
this[prop] = (...args) => {
this._connection[prop](...args);
}
}
}
}
// This is the added logic
reconnect(){
// Custom logic
}
}
Set the Connection instance to be a the prototype of PersistentConnection's instance:
function persistenChannel(channel){
const persistentChannel = {};
Object.setPrototypeOf(persistentChannel, channel);
persistentChannel.reconnect = () => {
// custom logic
}
}
This is the most "automatic" way I could think of.. But it just down right ugly, and the custom functions need to be declared each time an instance is created.
I still feel like I'm missing something, something like Ruby's magical method_missing (or pythons __getattr__) function which is called just before a method is missing exception is thrown and lets you define "safety net" logic (like delegating all calls to the inner _connection object.
Is there a better way to achieve this functionality?
Thanks a lot [=
Lets start from what we have. In any case, most of the functionaliy will be performed by vendor object. We do not know details realization so we can't rely that this object has no state. This mean, that in any case we need new connection object for the new persistentConnection. This can be achieved with proxy object
Lets try to do this:
function Connection() {
this.connect = () => console.log('connected by Connection class');
this.disconnect = () => console.log('disconnected by Connection class');
}
function persistantConnectionFactory() {
function PersistentConnection() {
this.checkConnection = () => console.log('no connection');
}
const instance = new PersistentConnection();
const proxy = new Proxy(instance, {
get: function (target, name) {
if (!(name in target)) {
console.log('adding new prototype')
Object.setPrototypeOf(instance, new Connection())
}
return target[name];
}
});
return proxy;
}
var c = persistantConnectionFactory();
c.checkConnection();
c.connect();
Does this solution good? I think - not. Without very good reasons this adds complexity without any value. Prototype should be enough.
What I want looks like this:
function bindFunctions(bindFunction, callbackFunction) {
// Add binding so that I can call the callbackFunction if the bindFunction is called
}
function log(message) {
console.log(message);
}
function notifyUser() {
alert('Something');
}
bindFunctions(log, notifyUser);
log('Error'); // Now the notifyUser-functions should be called and "Something" printed to the alert-box
bindFunctions($('.element').click, function() {/* CODE */}); // Or this: but I don't know if this is even possible because this is not the event-function but the binding-function of the click-event
Important: I have no influence on the bindFunction so it's not possible to implement a trigger there.
It's an attachment of a callback on any kind of existing function. Do you know how or if this is possible?
I believe you're looking at it the wrong way. What you need is some good old dependency inversion. Whatever code needs log has to receive it from a higher-level component (e.g. the composition root of your application). You're then free to implement a straightforward wrapper that calls notifyUser and inject it instead of the actual log.
I've linked some articles taking an OO perspective, but feel free to translate to a more functional model (the approaches are equivalent). In your case, you're using closures (which are, under a certain light, "equivalent" to objects with a single anonymous method).
The way you have to do to add a callback to a function is this:
var foo = function(number, callback){
number += 2;
callback(number);
}
foo(2, function(result){
window.alert(result)
});
https://jsfiddle.net/6dpz88md/
Good luck
Let's say I'm creating a chat system in javascript.
var ChatController = function() {
this.receiveMessageInteractor = new ReceiveMessageInteractor(this);
// ReceiveMessageInteractor delegate
this.didReceiveMessage = function(message) {
// ...
};
};
The ChatController also does some other stuff related to creating the html for the messages, but that's not important here.
The ChatController sets himself as a delegate of the ReceiveMessageInteractor, which will call the didReceiveMessage when a new message arrives.
var ReceiveMessageInteractor = function(delegate) {
this.observer = NotificationCenter.addObserver('DidReceiveMessageNotification' , function(data) {
var message = data['message'];
// format some message data
delegate.didReceiveMessage(message)
});
};
The ReceiveMessageInteractor just subscribes to a notification (NotificationCenter here is similar to the iOS one), does some formatting with the data and passes a message object to the delegate;
When the chat view goes of the screen (html gets deleted), my MenuController stops holding a pointer to ChatController, in which case I'd like it to be deleted, along with ReceiveMessageInteractor and observer.
The problem is that Javascript has no weak references, so ReceiveMessageInteractor is holding a pointer to ChatController, and even if ChatController wasn't holding a pointer to ReceiveMessageInteractor, my ChatController would still be alive, because the notification callback is holding a pointer to it (delegate).
So even if ReceiveMessageInteractor stopped existing, my ChatController would still not go away when the MenuController stops holding a pointer to it (because I can't have a weak reference inside the notification callback).
How do I solve this problem?
How do I solve this problem?
By understanding JavaScript. The problem is not that "Javascript has no weak references", the problem is that you don't know how to work without them because you come from a language that has them.
How would you remove that reference in any other language that doesn't have weak refs natively? Let's say C++. You would do like everyone does, including the implementors of the compiler/garbage collector/weak refs you're used to: you clean up after yourself.
function ChatController() {
this.receiveMessageInteractor = new ReceiveMessageInteractor(this);
// ReceiveMessageInteractor delegate
this.didReceiveMessage = function didReceiveMessage(message) {
// ...
};
this.destroy = function destroy() {
this.receiveMessageInteractor.destroy();
};
};
function ReceiveMessageInteractor(delegate) {
function callback(data) {
var message = data.message;
// format some message data
delegate.didReceiveMessage(message);
}
this.observer = NotificationCenter.addObserver('DidReceiveMessageNotification', callback);
this.destroy = function destroy() {
// Or however you NotificationCenter works, I don't know
NotificationCenter.removeObserver('DidReceiveMessageNotification', callback);
};
};
The Observer pattern implies resource management, even though it's not obvious (how is an "observation" relationship a resource??). Acquire and release. No hand-holding.
Also, notice the change in style. And please, learn the language, use prototypes, and, although not everyone will agree with me on this point, do not assign methods in the constructor.
edit: I forgot to add: ReceiveMessageInteractor? Really? What's wrong with MessageReceiver or something in that vein?
Your problem is not with the absence of weak references. All of your objects continue to have a hard reference, all originating from your NotificationCenter.
The NotificationCenter has a reference to the data handler, which has closure access to it's parent ReceiveMessageInteractor instance, as well as access to the delegate variable. Removing a reference to delegate from elsewhere won't break the anonymous function's access to it, therefore it stays.
What you'll need to do is add a .cleanup() method to each Controller that is called when it is removed.
In the ChatController.cleanup() method, you would want to call a method to remove the observer, something along the lines of this.receiveMessageInteractor.observer.unsubscribe().
The .unsubscribe() method should be defined in the NotificationCenter and remove the function(data) { ... } method you defined in .addObserver() from whatever data structure is holding it (or further down the line).
This is the same kind of pattern Facebook utilized in it's React framework + Flux architecture. Each component has a componentWillUnmount() method that assists in cleaning up data event handlers just like yours.
I'm looking for an elegant way to build an event-driven architecture where modules (scripts) are completely independent and decoupled from each other and rely only on Mediator for communication. Let's consider typical example:
var SomeModule = function () {...};
SomeModule.init = function ()
{
Mediator.register ('SomeEvent', this.onSomeEvent, this);
Mediator.register ('OtherEvent', this.onOtherEvent, this);
};
SomeModule.onSomeEvent = function (data)
{
var x = data.x;
var y = data.y;
// ........
Mediator.dispatch ('ThirdEvent', {name: 'Liza', gender: 1});
// now all modules registered for 'ThirdEvent' will get their callbacks executed
};
Typical Mediator operates as a dictionary routing calls from event name to according callback array to execute callbacks from. Now the problem lies in optimization: Mediator.dispatch (...) introduces dynamic objects and therefore polymorphic code which will remain slow and unoptimized when executed in V8. Some events will be fired 60 times per second and will have multiple callbacks, so it will surely benefit from optimizations.
What is the most elegant way to make this code monomorphic without introducing large boilerplate code for every new event?
EDIT: replaced .bind(this) with supplying this as context param as suggested in the comments.
60 times per second for this sort of operation is nothing.
That said if you want to optimize it, the most obvious bottleneck here will be definitely calling a function created using the native .bind function. You should always (I am not joking about always)use a homemade bind as the first thing when optimizing:
function bind(fn, ctx) {
return function() {
return fn.apply(ctx, arguments);
};
}
This doesn't do the same thing as Function.prototype.bind at all, which is the point: it does exactly what you would want bind to do and nothing more.
I have a simple JavaScript function that uses two delegates to (asynchronously) get one value back:
function getMyUserName() {
context.load(user);
context.executeQueryAsync(onGetMyUserNameSuccess, onGetMyUserNameFail);
}
function onGetMyUserNameSuccess() {
return user.get_title();
}
function onGetMyUserNameFail(sender, args) {
return args.get_message();
}
The "context" and "user" variables are already set and initialized, and the first delegate ("onGetMyUserNameSuccess") is getting the correct answer. The question is how I can test the "getMyUserName" function with Jasmine?. If I use "runs", I have no way to know the response from the delegates (also I don't see any way to know if the delegates are called). I tried to set spies to mock the delegates, but probably I didn't it correctly (I'm just starting with Jasmine).
Any help will be very welcome.
Thanks in advance,
Gustavo
In most of the cases when you have to work with async code, you should call the function by yourself. But not directly but in the way your code would call it. So in your case spy on context.executeQueryAsync and use spy.mostRecentCall.args to get the reference to the function and then call them.
var async = jasmin.spyOn(context, 'executeQueryAsync');
async.mostRecentCall.args[0]()
var args = {get_message: jasmine.createSpy()}
async.mostRecentCall.args[1]({}, args);
expect(args.get_message.toHaveBeenCalled());
Note that there is the sinon framework that have a bunch of methodes to automatically call callbacks