I am curious about current best practices for creating streams from sources that may not conform to an existing stream creation method (https://github.com/cujojs/most/blob/master/docs/api.md)
Example using Firebase's ref.on('child_added', function(snap){}):
most.fromEvent('child_added', ref) //ERROR
I can't use .fromEvent... although ref implements some sort of on, it does not seem to conform to the EventEmitter interface (addEventListener, removeEventListener)
ref.on('child_added', function(snap){ emitter.emit('value', snap) })
most.fromEvent('value', emitter)
Manually emitting events, is the best I can think of at the moment...
// https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/create.md
Rx.Observable.create(function(observer){
ref.on('child_added', function(snap){ observer.next(snap) })
})
Is there a similar mechanism to custom create a stream, a la Rx?
Are there better ways I am missing?
Check on how to use #most/create
https://github.com/mostjs/create
It allows to manually emit events - similar to how you would do it with rxJS
Another option might be to shim the interface that your firebase library exposes to fit most's fromEvent constructor.
Looking at the source code for fromEvent, we can see that it supports two interfaces for event sources:
{ addEventListener, removeEventListener } — the EventTarget interface, commonly implemented by DOM elements
{ addListener, removeListener } — the EventEmitter interface, found often in node libraries
With that knowledge, we can implement a shim function to create a stream from the { on, off } interface:
function fromEvent (eventName, source) {
if (typeof source.on === 'function' && typeof source.off === 'function') {
return most.fromEvent(eventName, {
addListener: source.on,
removeListener: source.off
});
} else {
return most.fromEvent.apply(null, arguments)
}
}
This can be nicer than using create, as the EventEmitterSource performs scheduling of the event on the next tick of the event loop, and handles disposing of the event listener when the stream ends.
Related
jQuery holds references to DOM nodes in its internal cache until I explicitly call $.remove(). If I use a framework such as React which removes DOM nodes on its own (using native DOM element APIs), how do I clean up jQuery's mem cache?
I'm designing a fairly large app using React. For those unfamiliar, React will tear down the DOM and rebuild as needed based on its own "shadow" DOM representation. The part works great with no memory leaks.
Flash forward, we decided to use a jQuery plugin. After React runs through its render loop and builds the DOM, we initialize the plugin which causes jQuery to hold a reference to the corresponding DOM nodes. Later, the user changes tabs on the page and React removes those DOM elements. Unfortunately, because React doesn't use jQuery's $.remove() method, jQuery maintains the reference to those DOM elements and the garbage collector never clears them.
Is there a way I can tell jQuery to flush its cache, or better yet, to not cache at all? I would love to still be able to leverage jQuery for its plugins and cross-browser goodness.
jQuery keeps track of the events and other kind of data via the internal API jQuery._data() however due to this method is internal, it has no official support.
The internal method have the following signature:
jQuery._data( DOMElement, data)
Thus, for example we are going to retrieve all event handlers attached to an Element (via jQuery):
var allEvents = jQuery._data( document, 'events');
This returns and Object containing the event type as key, and an array of event handlers as the value.
Now if you want to get all event handlers of a specific type, we can write as follow:
var clickHandlers = (jQuery._data(document, 'events') || {}).click;
This returns an Array of the "click" event handlers or undefined if the specified event is not bound to the Element.
And why I speak about this method? Because it allow us tracking down the event delegation and the event listeners attached directly, so that we can find out if an event handler is bound several times to the same Element, resulting in memory leaks.
But if you also want a similar functionality without jQuery, you can achieve it with the method getEventHandlers
Take a look at this useful articles:
getEventHandlers
getEventListeners - chrome
getEventListeners - firebug
Debugging
We are going to write a simple function that prints the event handlers and its namespace (if it was specified)
function writeEventHandlers (dom, event) {
jQuery._data(dom, 'events')[event].forEach(function (item) {
console.info(new Array(40).join("-"));
console.log("%cnamespace: " + item.namespace, "color:orangered");
console.log(item.handler.toString());
});
}
Using this function is quite easy:
writeEventHandlers(window, "resize");
I wrote some utilities that allow us keep tracking of the events bound to DOM Elements
Gist: Get all event handlers of an Element
And if you care about performance, you will find useful the following links:
Leaking Memory in Single Page Apps
Writing Fast, Memory-Efficient JavaScript
JavaScript Memory Profiling
I encourage anybody who reads this post, to pay attention to memory allocation in our code, I learn the performance problems ocurrs because of three important things:
Memory
Memory
And yes, Memory.
Events: good practices
It is a good idea create named functions in order to bind and unbind event handlers from DOM elements.
If you are creating DOM elements dynamically, and for example, adding handlers to some events, you could consider using event delegation instead of keep bounding event listeners directly to each element, that way, a parent of dynamically added elements will handle the event. Also if you are using jQuery, you can namespace the events ;)
//the worse!
$(".my-elements").click(function(){});
//not good, anonymous function can not be unbinded
$(".my-element").on("click", function(){});
//better, named function can be unbinded
$(".my-element").on("click", onClickHandler);
$(".my-element").off("click", onClickHandler);
//delegate! it is bound just one time to a parent element
$("#wrapper").on("click.nsFeature", ".my-elements", onClickMyElement);
//ensure the event handler is not bound several times
$("#wrapper")
.off(".nsFeature1 .nsFeature2") //unbind event handlers by namespace
.on("click.nsFeature1", ".show-popup", onShowPopup)
.on("click.nsFeature2", ".show-tooltip", onShowTooltip);
Circular references
Although circular references are not a problem anymore for those browsers that implement the Mark-and-sweep algorithm in their Garbage Collector, it is not a wise practice using that kind of objects if we are interchanging data, because is not possible (for now) serialize to JSON, but in future releases, it will be possible due to a new algorithm that handles that kind of objects. Let's see an example:
var o1 = {};
o2 = {};
o1.a = o2; // o1 references o2
o2.a = o1; // o2 references o1
//now we try to serialize to JSON
var json = JSON.stringify(o1);
//we get:"Uncaught TypeError: Converting circular structure to JSON"
Now let's try with this other example
var freeman = {
name: "Gordon Freeman",
friends: ["Barney Calhoun"]
};
var david = {
name: "David Rivera",
friends: ["John Carmack"]
};
//we create a circular reference
freeman.friends.push(david); //freeman references david
david.friends.push(freeman); //david references freeman
//now we try to serialize to JSON
var json = JSON.stringify(freeman);
//we get:"Uncaught TypeError: Converting circular structure to JSON"
PD: This article is about Cloning Objects in JavaScript. Also this gist contain demos about cloning objects with circular references: clone.js
Reusing objects
Let's follow some of the programming principles, DRY (Don't Repeat Yourself) and instead of creating new objects with similar functionality, we can abstract them in a fancy way. In this example I will going to reuse an event handler (again with events)
//the usual way
function onShowContainer(e) {
$("#container").show();
}
function onHideContainer(e) {
$("#container").hide();
}
$("#btn1").on("click.btn1", onShowContainer);
$("#btn2").on("click.btn2", onHideContainer);
//the good way, passing data to events
function onToggleContainer(e) {
$("#container").toggle(e.data.show);
}
$("#btn1").on("click.btn1", { show: true }, onToggleContainer);
$("#btn2").on("click.btn2", { show: false }, onToggleContainer);
And there are a lot of ways to improve our code, having an impact on performance, and preventing memory leaks. In this post I spoke mainly about events, but there are other ways that can produce memory leaks. I suggest read the articles posted before.
Happy reading and happy coding!
If your plugin exposes a method to programatically destroy one of its instances (i.e. $(element).plugin('destroy')), you should be calling that in the componentWillUnmount lifecycle of your component.
componentWillUnmount is called right before your component is unmounted from the DOM, it's the right place to clean up all external references / event listeners / dom elements your component might have created during its lifetime.
var MyComponent = React.createClass({
componentDidMount() {
$(React.findDOMNode(this.refs.jqueryPluginContainer)).plugin();
},
componentWillUnmount() {
$(React.findDOMNode(this.refs.jqueryPluginContainer)).plugin('destroy');
},
render() {
return <div ref="jqueryPluginContainer" />;
},
});
If your plugin doesn't expose a way to clean up after itself, this article lists a few ways in which you can try to dereference a poorly thought out plugin.
However, if you are creating DOM elements with jQuery from within your React component, then you are doing something seriously wrong: you should almost never need jQuery when working with React, since it already abstracts away all the pain points of working with the DOM.
I'd also be wary of using refs. There are only few use cases where refs are really needed, and those usually involve integration with third-party libraries that manipulate/read from the DOM.
If your component conditionally renders the element affected by your jQuery plugin, you can use callback refs to listen to its mount/unmount events.
The previous code would become:
var MyComponent = React.createClass({
handlePluginContainerLifecycle(component) {
if (component) {
// plugin container mounted
this.pluginContainerNode = React.findDOMNode(component);
$(this.pluginContainerNode).plugin();
} else {
// plugin container unmounted
$(this.pluginContainerNode).plugin('destroy');
}
},
render() {
return (
<div>
{Math.random() > 0.5 &&
// conditionally render the element
<div ref={this.handlePluginContainerLifecycle} />
}
</div>
);
},
});
How about do this when the user exits the tab:
for (x in window) {
delete x;
}
This is much better to do, though:
for (i in $) {
delete i;
}
I have some client side logic (I have a little 3d world where objects interacts), and I would like to add some events listener like this:
window.addEventListener("myAmazingEvent", () => {doSomethingAmazing})
How can I implement this eventListener to my own class? Like:
class Person {
construcor() {
this.listener = new SomeJavascriptEventListener()
}
crouched() {
this.listener.call("onCrunch")
}
const a = new Person()
a.addEventListener("onCrunch", () => {a.startSinging()})
What javascript built in classes can provide this behaviour to me?
JavaScript's standard library doesn't have any direct event emitter support. There are lots of event emitter libraries you can find with a search, but none of them is built-in.
You can:
Use one of the pre-built, pre-tested event emitter libraries that already exist (look for "event emitter" or "publish/subscribe" or "pub/sub").
Use something built into the environment you're running your code in. Node.js has an EventEmitter class. On browsers, you could create a DOM element that you keep in your class instance (no need for it to be in the document) and use it to store event listeners, then use dispatchEvent to send events to it. (Though that's not really simpler than the next option.)
Build your own by maintaining an array or Set of event listeners for each event type that you loop through and call when you need to emit an event.
All three are viable options.
But to give you an idea, a class with very basic event handling looks like this:
class Example {
#eventHandlers = {
"some-event": new Set(),
"another-event": new Set(),
};
on(eventName, handler) {
const handlers = this.#eventHandlers[eventName];
if (!handlers) {
throw new Error(`Invalid event name "${eventName}"`);
}
handlers.add(handler);
}
off(eventName, handler) {
const handlers = this.#eventHandlers[eventName];
if (!handlers) {
throw new Error(`Invalid event name "${eventName}"`);
}
handlers.delete(handler);
}
#trigger(eventName, ...eventArgs) {
const handlers = this.#eventHandlers[eventName];
// assert(!!handlers);
for (const handler of handlers) {
try {
handler(...eventArgs);
} catch { // (Add (e) if your environment doesn't support optional catch bindings)
}
}
}
doSomething() {
// In this example, "doing something" triggers the `some-event` event
this.#trigger("some-event", "something happened");
}
}
const e = new Example();
e.on("some-event", (msg) => console.log(`Handler one: received "${msg}"`));
e.on("some-event", (msg) => console.log(`Handler two: received "${msg}"`));
e.doSomething();
That uses relatively modern things (private fields, optional catch bindings), but you can adapt it as needed.
There are a dozen or more ways to skin this cat. Cross-talk between nandlers, cancelling events, passing in some kind of Event object, etc., etc., etc. But the fundamentals are:
Registering handlers (on in the example)
Unregistering handlers (off in the example)
Triggering events (#trigger in the example)
I'm trying to use peer js functionality where we create peers and use the respective event listeners i.e. when the peer is created, closed, connected and other stuff, and i'm trying to use it inside an event listener to make it work something like a service. Something like this:
class Demo extends EventEmitter {
private peer: Peer | null = null;
createPeerConnection() {
this.peer = new Peer();
this.peer.on('open', () => {
// Some stuff done
this.emit("Peer");
});
this.peer.on('close', () => {
// Some more stuff done
this.emit("Closed");
});
}
closePeerConnection() {
this.peer = null;
}
I know the peer has the destroy method, but let's say if for some reason I set the object to null, will the connected event listeners also be removed?
...when object is set to null in Javascript?
Objects can't be set null in JavaScript, but variables or properties referring to those objects can be. If that variable/property is the only one referring to the object, the object is eligible for garbage collection. So while the event listeners won't be removed per se, in the normal case the object goes away and it doesn't really matter (and if the object was the only thing referencing those event listeners, then they, too, are eligible for garbage collection).
There are things that can get in the way — other references to the object, or in some cases or some environments if the event listeners have a reference to the object, that circuluar relationship can keep them both around (there was a recent bug in browsers around this and ResizeObserver and IntersectionObserver). But in general, they all just go away (eventually).
To be absolutely sure, of course, proactively remove the listeners.
I am currently implementing a Bluetooth Library for Node.js that has support for macOS, Linux and Windows. To achieve cross platform compatibility I am using native, platform specific code (Objective-C, C++ & C) that use Node.js' EventEmitter and will trigger events whenever an asynchronous Bluetooth operation has completed or some other device has triggered an event for some reason.
The data format for these events look very differently and I would like to normalize them so users of my library will get there events in one single format, not matter which platform they are on.
Of course, I can attach event handlers to the native EventEmitters, transform and normalize the data and trigger Events with that normalized data in my own library.
The problem with that is that the users of the library will be able to attach - and - remove events to my library and what that means is that if they attached an event to my library, let's say to "deviceDiscovered" like so:
const myListener = (device) => { /* ... */ };
bluetoothLibrary.on("deviceDiscovered", myListener);
My implementation would have to look a little something like this:
class BluetoothLibrary {
nativeAdapter = getAdapterForCurrentOS();
on(event, callback) {
this.nativeAdapter.on(event, (data) => {
const normalizedData = this.normalize(data)
callback(normalizedData);
});
}
off(event, callback) {
this.nativeAdapter.off(event, callback)
}
normalize(data) {
/* ... */
}
}
The problem with this is if someone wants to remove their event listeners again, like so:
const myListener = (device) => { /* ... */ };
bluetoothLibrary.on("deviceDiscovered", myListener);
bluetoothLibrary.off("deviceDiscovered", myListener);
Because of my implementation, the listener never really would be removed because I never really attach the reference to the callback that has been passed to me to the native adapter's EventEmitter.
I am wondering if there is a way to transform or pipe events through some transformations on the way before passing them on to an event listener.
Are there any Event Driven Architecture jQuery plugins?
Step 1: Subscribing
The subscribers subscribe to the event handler in the middle, and pass in a callback method, as well as the name of the event they are listening for...
i.e. The two green subscribers will be listening for p0 events. And the blue subscriber will be listening for p1 events.
Step 2: The p0 event is fired by another component to the Event Handler
A p0 event is fired to the Event Handler
The event handler notifies it's subscribers of the event, calling the callback methods they specified when they subscribed in Step 1: Subscribing.
Note that the blue subscriber is not notified because it was not listening for p0 events.
Step 3: The p1 event is fired a component to the Event Handler
The p1 event is fired by another component
Just as before except that now the blue subscriber receives the event through its callback and the other two green subscribers do not receive the event.
Images by leeand00, on Flickr
I can't seem to find one, but my guess is that they just call it something else in Javascript/jquery
Also is there a name for this pattern? Because it isn't just a basic publisher/subscriber, it has to be called something else I would think.
You probably don't need a plugin to do this. First of all, the DOM itself is entirely event driven. You can use event delegation to listen to all events on the root node (a technique that jQuery live uses). To handle custom events as well that may not be DOM related, you can use a plain old JavaScript object to do the job. I wrote a blog post about creating a central event dispatcher in MooTools with just one line of code.
var EventBus = new Class({Implements: Events});
It's just as easy to do in jQuery too. Use a regular JavaScript object that acts as a central broker for all events. Any client object can publish and subscribe to events on this object. See this related question.
var EventManager = {
subscribe: function(event, fn) {
$(this).bind(event, fn);
},
unsubscribe: function(event, fn) {
$(this).unbind(event, fn);
},
publish: function(event) {
$(this).trigger(event);
}
};
// Your code can publish and subscribe to events as:
EventManager.subscribe("tabClicked", function() {
// do something
});
EventManager.publish("tabClicked");
EventManager.unsubscribe("tabClicked");
Or if you don't care about exposing jQuery, then simply use an empty object and call bind and trigger directly on the jQuery wrapped object.
var EventManager = {};
$(EventManager).bind("tabClicked", function() {
// do something
});
$(EventManager).trigger("tabClicked");
$(EventManager).unbind("tabClicked");
The wrappers are simply there to hide the underlying jQuery library so you can replace the implementation later on, if need be.
This is basically the Publish/Subscribe or the Observer pattern, and some good examples would be Cocoa's NSNotificationCenter class, EventBus pattern popularized by Ray Ryan in the GWT community, and several others.
Though not a jQuery plugin, Twitter released a JavaScript framework called Flight which allows you to create component-based architectures, which communicate via events.
Flight is a lightweight, component-based JavaScript framework from Twitter. Unlike other JavaScript frameworks which are based around the MVC pattern, Flight maps behavior directly to DOM nodes.
Flight is agnostic to how requests are routed or which templating library you decide to use. Flight enforces strict separation of concerns. Components in Flight do not engage each other directly.
They broadcast their actions as events and those components subscribed to those events can take actions based on them. To make use of Flight, you will need the ES5-shim and jQuery along with an AMD loader.
Flight - A Lightweight, Component-Based JavaScript Framework From Twitter
There are actually two of them:
Listen (faster): http://plugins.jquery.com/project/Listen
Intercept (more advanced): http://plugins.jquery.com/project/Intercept
Could this serve as a ligthweight message passing framework?
function MyConstructor() {
this.MessageQueues = {};
this.PostMessage = function (Subject) {
var Queue = this.MessageQueues[Subject];
if (Queue) return function() {
var i = Queue.length - 1;
do Queue[i]();
while (i--);
}
}
this.Listen = function (Subject, Listener) {
var Queue = this.MessageQueues[Subject] || [];
(this.MessageQueues[Subject] = Queue).push(Listener);
}
}
then you could do:
var myInstance = new MyConstructor();
myInstance.Listen("some message", callback());
myInstance.Listen("some other message", anotherCallback());
myInstance.Listen("some message", yesAnotherCallback());
and later:
myInstance.PostMessage("some message");
would dispatch the queues
This can easily be accomplished using a dummy jQuery node as a dispatcher:
var someModule = (function ($) {
var dispatcher = $("<div>");
function init () {
_doSomething();
}
/**
#private
*/
function _doSomething () {
dispatcher.triggerHandler("SOME_CUSTOM_EVENT", [{someEventProperty: 1337}]);
}
return {
dispatcher: dispatcher,
init: init
}
}(jQuery));
var someOtherModule = (function ($) {
function init () {
someModule.dispatcher.bind("SOME_CUSTOM_EVENT", _handleSomeEvent)
}
/**
#private
*/
function _handleSomeEvent (e, extra) {
console.log(extra.someEventProperty) //1337
}
return {
init: init
}
}(jQuery));
$(function () {
someOtherModule.init();
someModule.init();
})
A recent development is msgs.js "Message oriented programming for JavaScript. Inspired by Spring Integration". It also supports communication via WebSockets.
msgs.js applies the vocabulary and patterns defined in the 'Enterprise Integration Patterns' book to JavaScript extending messaging oriented programming into the browser and/or server side JavaScript. Messaging patterns originally developed to integrate loosely coupled disparate systems, apply just as well to loosely coupled modules within a single application process.
[...]
Tested environments:
Node.js (0.6, 0.8)
Chrome (stable)
Firefox (stable, ESR, should work in earlier versions)
IE (6-10)
Safari (5, 6, iOS 4-6, should work in earlier versions)
Opera (11, 12, should work in earlier versions)
I have used the OpenAjax Hub for its publish/subscribe services. It's not a jQuery plugin, but a standalone JavaScript module. You can download and use the reference implementation from SourceForge. I like the hierarchical topic naming and the support for subscribing to multiple topics using wildcard notation.