(Angular) with many subscribers - javascript

What happens when you have too many subscribers? I have a directive that watches every route events, and I placed my directive inside of a NgFor.
I am just new to RxJS and I'm very concerned about the performance.

Performance Notes:
Event Loop:
All subscribing methods or functions are called as soon as an event fires, but not directly. They are handled by the Event Loop, and it can handle a lot of events firing at once.
I/O bound vs CPU bound functions:
But if the functions being called are not I/O bound, i.e. simple input output stuff, like logging, or calling Google Analytics, then performance will dip.
Imagine running Path Finding algorithm (A*, Dijsktra) on each event fired!
Unsubscribe as a best practice:
Another thing to keep in mind is to unsubscribe the event, in NgOnDestroy(), of the directive, it'll keep the potentially growing amount of events from spiraling out of control!

Related

What causes the Node.js EventEmitter warnings?

My node.js backend has a lot of mongoose.connection.useDb lines because it frequently needs to switch databases. Today I restarted my server and got this warnings:
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 connected listeners added to [NativeConnection].
It took me some time to find a solution, and I found that by just adding mongoose.connection.removeAllListeners() the warning dissapears. What does this mean, and what exactly is an event? It feels like if I remove all listeners that the code that used those databases (like when I needed to create a model for a schema) shouldn't work anymore, but that isn't the case.
What does this mean?
This warning indicates that you're registering 11 or more listeners for the same event or calling some code that is internally causing this to happen. The warning is because normal usage of an event emitter rarely needs 11 listeners for the same event.
Instead, this many listeners for the same event is usually an indication that you're registering for the same event over and over or repeatedly calling some function that causes the same listener over and over again. In your specific case it looks like you should perhaps use the noListener: true option when calling .useDb(). See the doc here and this troubleshooting report.
Failing to remove listeners that you are no longer using can create a regularly growing memory leak (just like the error message indicates) because nodejs can't tell that you no longer intend to use that listener. It's still registered for the event, the event can still occur and thus the listener (the ones you no longer intend to use) are still active. This takes additional memory inside the eventEmitter object and (perhaps more importantly), it may keep certain closure variables from getting garbage collected inside the listener callback function/scope.
So, whenever an eventEmitter object gets the 11th or more listener for the same event, it issues this warning.
If you show the actual code and context where this warning occurs, we could give you more specific advice about what you should/should not be doing in that code. The above is a generic description/advice because you didn't show your specific code and context.
What is an event?
This warning comes from an eventEmitter object which, given your explanation, is probably being used inside the database whenever you call .useDb(). Something you are doing with the database is causing it to register a listener for an event on an eventEmitter object. If you want to know more about events in the context of an eventEmitter object, I'd suggest reading the eventEmitter documentation.
In a nutshell, an eventEmitter object allows one to listen for events by calling obj.addListener("someEventName", fn) or the identical (but shorter) obj.on("someEventName, fn) where obj is an instance of the EventEmitter class. Then, other code can trigger events obj.emit("someEventName", someData). When an event is triggered, all registered listeners for that specific event name will have their callback called. Nodejs uses event objects and listeners like this in lots of places in its libraries. For example streams use listeners to listener for incoming data as in stream.on('data', myCallback).

Publish/Subscribe with CustomEvents in JavaScript

I've got the task to talk about event based communicatoin and the publish/subscribe based communication in JavaScript.
After thinking about it I wonder that the CustomEvents in JavaScript actually use the publish/subscribe pattern.
Dispatching a CustomEvent is like publishing new data or triggering the update function in the subscribers and creating an event listener is the same es subscribing to a publisher.
In other words every time a event is thrown every listener's callback is run is just the same as every time a publisher publishes new data, the subscriber's update functions are called.
Is this a correct solution or did I not got the key concepts fo the two patterns?

Should we consider the addEvenetListener method a loop?

As far as I understand, the addEvenetListener method will usually just listen to a certain event and when that event is triggered a callback function will be called to perform everything in the event handler code in that callback function.
addEventListener listens for each triggering of a certain event. To me it seems quite like a for each loop as initiated by the forEach() method.
I assume we could at least say both forEach() and addEvenetListener are loopish functions, though just functions (methods).
Javascript addEventListener follows the famous "don't call us, we will call you." Also known as the Hollywood principle.
In software engineering it's also called the observer or subscriber part as in the publisher/observer design pattern.
Basically when you call addEventListener for let's say the click event with a callback. It's going to call the core of JavaScript engine saying
"Hey I have a function that wants to be called everytime there is a click."
The JavaScript engine is going to store a reference to the callback. And then during the JavaScript event loop, everytime there is a click event, it's simply going to call all its references to callback.
So the loop is indeed happening inside the JavaScript event loop (which you have little control over). But your callback is a simple function that subscribed to a specific event and will be called at the right time to react to this event. There is no magic behind it.
In fact, your callback is not really listening for event, it just subscribes itself once to a specific event and then it's done. It might be called in the future, but it's surely not actively listening for it.
As far as I understand, in relation to the common JavaScript literature in 2017 (MDN), we shouldn't say it's a loop, because it's not one of the loops defined in JavaScript like for and while. We can indeed say it's an observer as it observers for each triggering of its associated event.
We don't iterate for each item in a collection, we observe for each triggering of the relevant event; One can say that the "for each" like behavior indicates "loopishness" and I personally find no flaw with that.

Does Functional Reactive Programming in JavaScript cause bigger problems with listener references?

In JavaScript the observer pattern is used quite often. There is one tricky thing with it and that's the references the subject keeps of the observers. They require cleanup. For regular applications I use the following rules of thumb:
If the subject has a life span shorter than (or equal to) the observer, I can just do subject.on('event', ...)
If the subject has a life span longer than the observer, I need to use observer.listenTo(subject, 'event', ...)
In the second case, the listenTo is aware of the life-cycle of the observer and it will automatically remove the listeners when it's time for the observer to die.
In modern day SPA (Single Page Application) style, where only parts of the application are active at any time this is something that becomes very important. If you combine that with web sockets, which are a perfect candidate for an event stream and most likely long lived, this becomes even more important.
With FRP, having something like an event stream representing changing values over time, I am (without knowing it) creating a lot of listeners. Each filter, map and flatMap creates a new stream that is tied (probably using a listener) to the previous one.
In my mind it seems quite tricky to determine how and when I need to remove those listeners. I can not imagine me being the first to think about this problem, yet I could not find much about this on the Internet.
I have seen some frameworks in other languages use weak references. JavaScript does not have the concept of weak references (WeakMap is not usable here). Even if it had though, it seems like a bad idea because it's unclear when garbage collection takes place.
How is this solved in the current frameworks?
Do the frameworks tie into the life-cycle of objects? If yes: how?
In RxJs, each Observer will, by default, have a separate listener on the original event source. So, if you have
var s = $('#textInput').keyupAsObservable()
s.subscribe(subscriber1);
s.map(function() {}).subscribe(subscriber2);
You'll have two keyup listeners. You can use .publish().refCount() to make an Observable maintain a single connection to its source.
In Bacon.js, Observables always maintain a single connection to their source.
In both libraries the connection to the source is created lazily (when an Observer is added) and removed automatically when the (last) Observer is removed. Therefore you don't have to manually manage the listeners.
However, in the case where the subject has a longer life span than the Observer, you'll have to make sure the observer stops its subscription when its lifespan ends, or you'll have a leak. Neither libraries have any "magical" way of managing this, because to the library, your Observer is just a function.
Personally I often create an Observable called death or whatever to signal the end-of-life for the Observer and then instead of subscribing to the subject I subscribe to subject.takeUntil(death).
Regarding Elm, my understanding is that you have set up your entire event network at once, so there's no possibility for leak; Observers cannot be added at a later stage.

Is publishing/subscribing to events after UI rendering a best practice regardless of framework?

I've inherited a rather large Javascript/ExtJS3 code base, and there are many instances of invoking events inside of the overridden initComponent method, after the call to "...superclass.initComponent.apply(this, arguments)". Specific events are being invoked on specific objects in a manner such as the following:
this.filter.on('filterUpdated', function(filter, params)
I've started converting the code to use a pub/sub paradigm instead, to reduce the coupling between objects and their specific event names, but quickly ran into issues when publishing and/or subscribing to events within initComponent (which in ExtJS executes before rendering). I need to fire an "INIT" event from the highest level component when the screen first loads, and I was either getting an error (due to ExtJS "templates" not having been rendered as it turns out), or events not firing at all.
Then I read the following in the ExtJS source for Ext.Component (from which all components extend) and I had an "aha" moment:
if (this.tpl) {
if (!this.tpl.compile) {
this.tpl = new Ext.XTemplate(this.tpl);
}
if (this.data) {
this.tpl[this.tplWriteMode](contentTarget, this.data);
delete this.data;
}
}
this.afterRender(this.container);
When I switched to both publishing the "INIT" event from my topmost component's afterRender method, and subscribing to all events from all other components from their afterRender methods, everything worked as I expected. And now I am just wondering, largely to validate my design....
Is this a generally accepted way of implementing pub/sub in an event driven UI? Regardless of framework even? Namely are the following 2 good principles, or are their other ways?
"Initialization events" should get published after all sub-components have rendered
All sub-components should subscribe to all events (to be on the safe side) after they have rendered
Thanks in advance
You have to balance the overhead of event handling vs. the possibility of missing significant events. In js/DOM land state is mutable.
For your #1 if you can identify a point in time when all your sub-components have rendered and subscribed, firing an init event makes sense.
For #2, it seems safe everyone to listen for events; however it could slow things down. If performance issues are apparent you may have to decide what events you don't care about and avoid subscribing.

Categories

Resources