Clear references to function - javascript

I need to clear memory in js, I have classes like this:
class A{
constructor(socket){
this.initSockets(socket);
}
classMethod(){
}
initSockets(socket){
socket.on('name', () => this.classMethod())
}
}
This class cannot be cleaned by the garbage collector, because as I understand socket saves the reference to a class method(memory snapshot point to socket.on), how properly I need "to null" this function, to delete the reference and let garbage collector delete this class? The project becomes a little big, so I can't change the way I use sockets.

Since 2018 some years have passed and now we write the year 2022;
By now we have stuff like WeakMap, WeakSet and WeakRefs... and the V8 Team has described how to accomplish exactly that with "Weak references and finalizers": https://v8.dev/features/weak-references
This is the procedure they suggest:
const gListenersRegistry = new FinalizationRegistry(({ socket, wrapper }) => {
socket.removeEventListener('message', wrapper); // 6
});
function addWeakListener(socket, listener) {
const weakRef = new WeakRef(listener); // 2
const wrapper = (ev) => { weakRef.deref()?.(ev); }; // 3
gListenersRegistry.register(listener, { socket, wrapper }); // 4
socket.addEventListener('message', wrapper); // 5
}
class MovingAvg {
constructor(socket) {
this.events = [];
this.listener = (ev) => { this.events.push(ev); }; // 1
addWeakListener(socket, this.listener);
}
}
For more details read the article above.

Related

Spy function with elementary JavaScript syntax [duplicate]

The main reason why I want it is that I want to extend my initialize function.
Something like this:
// main.js
window.onload = init();
function init(){
doSomething();
}
// extend.js
function extends init(){
doSomethingHereToo();
}
So I want to extend a function like I extend a class in PHP.
And I would like to extend it from other files too, so for example I have the original init function in main.js and the extended function in extended.js.
With a wider view of what you're actually trying to do and the context in which you're doing it, I'm sure we could give you a better answer than the literal answer to your question.
But here's a literal answer:
If you're assigning these functions to some property somewhere, you can wrap the original function and put your replacement on the property instead:
// Original code in main.js
var theProperty = init;
function init(){
doSomething();
}
// Extending it by replacing and wrapping, in extended.js
theProperty = (function(old) {
function extendsInit() {
old();
doSomething();
}
return extendsInit;
})(theProperty);
If your functions aren't already on an object, you'd probably want to put them there to facilitate the above. For instance:
// In main.js
var MyLibrary = {
init: function init() {
}
};
// In extended.js
(function() {
var oldInit = MyLibrary.init;
MyLibrary.init = extendedInit;
function extendedInit() {
oldInit.call(MyLibrary); // Use #call in case `init` uses `this`
doSomething();
}
})();
But there are better ways to do that. Like for instance, providing a means of registering init functions.
// In main.js
var MyLibrary = (function() {
var initFunctions = [];
return {
init: function init() {
var fns = initFunctions;
initFunctions = undefined;
for (var index = 0; index < fns.length; ++index) {
try { fns[index](); } catch (e) { }
}
},
addInitFunction: function addInitFunction(fn) {
if (initFunctions) {
// Init hasn't run yet, remember it
initFunctions.push(fn);
} else {
// `init` has already run, call it almost immediately
// but *asynchronously* (so the caller never sees the
// call synchronously)
setTimeout(fn, 0);
}
}
};
})();
Here in 2020 (or really any time after ~2016), that can be written a bit more compactly:
// In main.js
const MyLibrary = (() => {
let initFunctions = [];
return {
init() {
const fns = initFunctions;
initFunctions = undefined;
for (const fn of fns) {
try { fn(); } catch (e) { }
}
},
addInitFunction(fn) {
if (initFunctions) {
// Init hasn't run yet, remember it
initFunctions.push(fn);
} else {
// `init` has already run, call it almost immediately
// but *asynchronously* (so the caller never sees the
// call synchronously)
setTimeout(fn, 0);
// Or: `Promise.resolve().then(() => fn());`
// (Not `.then(fn)` just to avoid passing it an argument)
}
}
};
})();
There are several ways to go about this, it depends what your purpose is, if you just want to execute the function as well and in the same context, you can use .apply():
function init(){
doSomething();
}
function myFunc(){
init.apply(this, arguments);
doSomethingHereToo();
}
If you want to replace it with a newer init, it'd look like this:
function init(){
doSomething();
}
//anytime later
var old_init = init;
init = function() {
old_init.apply(this, arguments);
doSomethingHereToo();
};
The other methods are great but they don't preserve any prototype functions attached to init. To get around that you can do the following (inspired by the post from Nick Craver).
(function () {
var old_prototype = init.prototype;
var old_init = init;
init = function () {
old_init.apply(this, arguments);
// Do something extra
};
init.prototype = old_prototype;
}) ();
Another option could be:
var initial = function() {
console.log( 'initial function!' );
}
var iWantToExecuteThisOneToo = function () {
console.log( 'the other function that i wanted to execute!' );
}
function extendFunction( oldOne, newOne ) {
return (function() {
oldOne();
newOne();
})();
}
var extendedFunction = extendFunction( initial, iWantToExecuteThisOneToo );
2017+ solution
The idea of function extensions comes from functional paradigm, which is natively supported since ES6:
function init(){
doSomething();
}
// extend.js
init = (f => u => { f(u)
doSomethingHereToo();
})(init);
init();
As per #TJCrowder's concern about stack dump, the browsers handle the situation much better today. If you save this code into test.html and run it, you get
test.html:3 Uncaught ReferenceError: doSomething is not defined
at init (test.html:3)
at test.html:8
at test.html:12
Line 12: the init call, Line 8: the init extension, Line 3: the undefined doSomething() call.
Note: Much respect to veteran T.J. Crowder, who kindly answered my question many years ago, when I was a newbie. After the years, I still remember the respectfull attitude and I try to follow the good example.
This is very simple and straight forward. Look at the code. Try to grasp the basic concept behind javascript extension.
First let us extend javascript function.
function Base(props) {
const _props = props
this.getProps = () => _props
// We can make method private by not binding it to this object.
// Hence it is not exposed when we return this.
const privateMethod = () => "do internal stuff"
return this
}
You can extend this function by creating child function in following way
function Child(props) {
const parent = Base(props)
this.getMessage = () => `Message is ${parent.getProps()}`;
// You can remove the line below to extend as in private inheritance,
// not exposing parent function properties and method.
this.prototype = parent
return this
}
Now you can use Child function as follows,
let childObject = Child("Secret Message")
console.log(childObject.getMessage()) // logs "Message is Secret Message"
console.log(childObject.getProps()) // logs "Secret Message"
We can also create Javascript Function by extending Javascript classes, like this.
class BaseClass {
constructor(props) {
this.props = props
// You can remove the line below to make getProps method private.
// As it will not be binded to this, but let it be
this.getProps = this.getProps.bind(this)
}
getProps() {
return this.props
}
}
Let us extend this class with Child function like this,
function Child(props) {
let parent = new BaseClass(props)
const getMessage = () => `Message is ${parent.getProps()}`;
return { ...parent, getMessage} // I have used spread operator.
}
Again you can use Child function as follows to get similar result,
let childObject = Child("Secret Message")
console.log(childObject.getMessage()) // logs "Message is Secret Message"
console.log(childObject.getProps()) // logs "Secret Message"
Javascript is very easy language. We can do almost anything. Happy JavaScripting... Hope I was able to give you an idea to use in your case.
Use extendFunction.js
init = extendFunction(init, function(args) {
doSomethingHereToo();
});
But in your specific case, it's easier to extend the global onload function:
extendFunction('onload', function(args) {
doSomethingHereToo();
});
I actually really like your question, it's making me think about different use cases.
For javascript events, you really want to add and remove handlers - but for extendFunction, how could you later remove functionality? I could easily add a .revert method to extended functions, so init = init.revert() would return the original function. Obviously this could lead to some pretty bad code, but perhaps it lets you get something done without touching a foreign part of the codebase.

Javascript ES6 Classes composition

i'm struggling in what would be a good practice or better approach to communicate 'sibling classes in es6' quoted because they haven't a real parent class, by definition.
let me explain better:
class Car {
constructor(typeOfMotor){
this.motor = typeOfMotor;
this.mount();
this.addListener();
}
mount() {
// Some async logic here, and this will return true or false;
}
addListener(driver) {
// Here i want to listen this.mount method and,
// when return true, then call the ride method in the driver
// If true:
driver.ride();
}
}
class Driver {
constructor(driverName) {
this.name = driverName;
}
ride(){
console.log('Highway to hell!');
}
}
class Race {
constructor() {
this.init();
}
init() {
this.car = new Car('v8');
this.driver = new Driver('michael');
}
}
var race = new Race;
race.car.addListener(race.driver);
So basically, i have some environments where i don't need to extend classes, because i want to keep them as encapsulated as possible.
And i have this top Class (not parent because the others are not inheriting anything, though).
And the question is simple, what would be the best way to create this communication between the elements.
You can pass the Driver class instance to the Car constructor and invoke any method within this instance.
I would rethink the structure and business logic here and check what kind of responsibility each component should handle.
For example, i think it's up to the driver to decide when to drive but of course the car should signal when it is ready.
So the car shouldn't invoke driver.ride and instead just signal the driver i'm on and ready to go, and the driver should invoke the driving function.
But that's arguable of course.
Here is a running example of your code (a bit modified):
class Car {
constructor(typeOfMotor, driver) {
this.motor = typeOfMotor;
this.mounted = this.mount();
this.driver = driver;
}
mount = () => {
console.log('fetching data...');
setTimeout(() => {
this.drive()
}, 1500)
}
drive = () => {
// Here i want to listen this.mount method and,
// when return true, then call the ride method in the driver
// If true:
this.driver.ride();
}
}
class Driver {
constructor(driverName) {
this.name = driverName;
}
ride = () => {
console.log('Highway to hell!');
}
}
class Race {
constructor() {
this.init();
}
init = () => {
this.driver = new Driver('michael');
this.car = new Car('v8', this.driver);
}
}
var race = new Race();

How is an event passed to a javascript method?

There are several answers for how to pass an "artificial" event in javascript.
What I dont understand is how is the event passed to the method AND event if not passed be accessible by directly using the "event" variable even though it doesnt seem to be declared anywhere.
Can someone explain this?
Thanks in advance
Here is a rudimentary event listener:
class EventCaller {
constructor() {
this.listeners = [];
}
addListener(obj) {
if (obj.trigger) { this.listeners.push(obj); }
}
trigger(event, ..data) {
this.listeners.forEach((listener) => listener.trigger(event, ...data));
}
}
class EventListener {
constructor() { this.eventsListeningTo = []; }
listenTo(item) {
if (!item.addListener) { throw new Error('Cannot add listener error'); }
item.addListener(this);
}
trigger(event, ...data) {
if (this[`on${event}`]) {this[`on${event}`](...data)}
}
onFoo({bar, foo}) {
console.log(bar, foo);
}
}
Then as an example you can create an EventCaller:
const eventAgg = new EventCaller();
Then create a few event listeners
const a = new EventListener();
const b = new EventListener();
Then a and b can listen on eventAgg events
a.listenTo(eventAgg);
b.listenTo(eventAgg);
So if now I trigger
eventAgg.trigger('Foo', {bar: 'lemons', foo: 42});
Now both a and b will console log out lemons, 42 since they are both listening on that pseudo event.
This is just basics. jquery, Backbone, angular etc all implement this in different ways (I am sure) but it all comes down to callbacks (or even Promises in newer code)

How to unsubscribe from a socket.io subscription?

Suppose there are objects making subscriptions to a socket server like so:
socket.on('news', obj.socketEvent)
These objects have a short life span and are frequently created, generating many subscriptions. This seems like a memory leak and an error prone situation which would intuitively be prevented this way:
socket.off('news', obj.socketEvent)
before the object is deleted, but alas, there isn't an off method in the socket. Is there another method meant for this?
Edit: having found no answer I'm assigning a blank method to overwrite the wrapper method for the original event handler, an example follows.
var _blank = function(){};
var cbProxy = function(){
obj.socketEvent.apply(obj, arguments)
};
var cbProxyProxy = function(){
cbProxy.apply ({}, arguments)
}
socket.on('news', cbProxyProxy);
// ...and to unsubscribe
cbProxy = _blank;
From looking at the source of socket.io.js (couldn't find it in documentation anywhere), I found these two functions:
removeListener = function(name, fn)
removeAllListeners = function(name)
I used removeAllListeners successfully in my app; you should be able to choose from these:
socket.removeListener("news", cbProxy);
socket.removeAllListeners("news");
Also, I don't think your solution of cbProxy = _blank would actually work; that would only affect the cbProxy variable, not any actual socket.io event.
If you want to create listeners that "listens" only once use socket.once('news',func). Socket.io automatically will distroy the listener after the event happened - it's called "volatile listener".
Looking at the code of current version of Socket.io Client (1.4.8) it seems that off, removeAllListeners, removeEventListener are all pointing to the same function.
Calling any of those, providing event name and/or callback, gives the desired result. Not providing anything at all seems to reset everything.
Please do be cautious about the fn/callback argument. It has to be the same instance used in the code.
Example:
var eventCallback = function(data) {
// do something nice
};
socket.off('eventName', eventCallback);
Would work as expected.
Example (will also work):
function eventCallback(data) {
// do something nice
}
socket.off('eventName', eventCallback);
Please be cautious that the callback you are trying to remove is the one that you passed in (this one can bring a lot of confusion and frustration).
This example implements a wrapper around initial callback, trying to remove that would not work as the real callback being added is an undisclosed closure instance: http://www.html5rocks.com/en/tutorials/frameworks/angular-websockets/
Here is the link to that specific line in the codebase: https://github.com/socketio/socket.io-client/blob/master/socket.io.js#L1597
Socket.io version 0.9.16 implements removeListener but not off.
You can use removeListener instead of off when unsubscribing, or simply implement off as follows:
var socket = io.connect(url);
socket.off = socket.removeListener;
If you are using the Backbone listenTo event subscription approach, you'll need to implement the above as Backbone calls off when unsubscribing events.
I found that in socket.io 0.9.11 and Chrome24 socket.io removeListener doesn't work.
this modified version works for me:
EventEmitter.prototype.removeListener = function (name, fn) {
if (this.$events && this.$events[name]) {
var list = this.$events[name];
if (io.util.isArray(list)) {
var pos = -1;
for (var i = 0, l = list.length; i < l; i++) {
if (list[i].toString() === fn.toString() || (list[i].listener && list[i].listener === fn)) {
pos = i;
break;
}
}
if (pos < 0) {
return this;
}
list.splice(pos, 1);
if (!list.length) {
delete this.$events[name];
}
} else {
if (list.toString() === fn.toString() || (list.listener && list.listener === fn)) {
delete this.$events[name];
}
}
}
return this;
};
Since I had a spot of troubles making this work figured I'd chime in here as well, along with a nice updated answer for 2017. Thanks to #Pjotr for pointing out that it has to be the same callback instance.
Example with Angular2 TypeScript in a socket-io.subscriber service. Note the "newCallback" wrapper
private subscriptions: Array<{
key: string,
callback: Function
}>;
constructor() {
this.subscriptions = [];
}
subscribe(key: string, callback: Function) {
let newCallback = (response) => callback(response);
this.socket.on(key, newCallback);
return this.subscriptions.push({key: key, callback: newCallback}) - 1;
}
unsubscribe(i: number) {
this.socket.removeListener(this.subscriptions[i].key, this.subscriptions[i].callback);
}
Removing an event listener on the client
var Socket = io.connect();
Socket.removeListener('test', test);
Also on java client, it can be done the same way with the Javascript client. I've pasted from socket.io.
// remove all listeners of the connect event
socket.off(Socket.EVENT_CONNECT);
listener = new Emitter.Listener() { ... };
socket.on(Socket.EVENT_CONNECT, listener);
// remove the specified listener
socket.off(Socket.EVENT_CONNECT, listener);
Pre-store the events using an array, and by the time you need to unsubscribe them, use the off method, which is a built in method from socket.io:
// init
var events = []
// store
events.push("eventName")
// subscribe
socket.on("eventName", cb)
// remove
events = events.filter(event => event!="eventName")
// unsubscribe
socket.off("eventName")
To add to #Andrew Magee, here is an example of unsubscribing socket.io events in Angular JS, and of course works with Vanilla JS:
function handleCarStarted ( data ) { // Do stuff }
function handleCarStopped ( data ) { // Do stuff }
Listen for events:
var io = $window.io(); // Probably put this in a factory, not controller instantiation
io.on('car.started', handleCarStarted);
io.on('car.stopped', handleCarStopped);
$scope.$on('$destroy', function () {
io.removeListener('car.started', handleCarStarted);
io.removeListener('car.stopped', handleCarStopped);
});
This has helped me in both Angular 8 and React 16.8:
receiveMessage() {
let newCallback = (data) => {
this.eventEmitter.emit('add-message-response', data);
};
this.socket.on('add-message-response', newCallback);
this.subscriptions.push({key: 'add-message-response', callback: newCallback});
}
receiveMessageRemoveSocketListener() {
this.findAndRemoveSocketEventListener('add-message-response');
}
findAndRemoveSocketEventListener (eventKey) {
let foundListener = this.subscriptions.find( (subscription) => subscription.key === eventKey );
if(!foundListener) {
return;
}
this.socket.removeListener(foundListener.key, foundListener.callback);
this.subscriptions = this.subscriptions.filter( (subscription) => subscription.key !== eventKey );
}
Reason for using an Array of Subscriptions is that when you Subscribe to an event multiple times and you don't remove an unsubscribed subscription from the Subscription list you will most probably be right at first time you remove the subscription from the list, but later subscriptions will not be removed as you will be finding first instance only every time you unsubscribe the event.
You can simply call receiveMessage(); to subscribe to an the event and receiveMessageRemoveSocketListener(); to Unsubscribe.

Javascript: Extend a Function

The main reason why I want it is that I want to extend my initialize function.
Something like this:
// main.js
window.onload = init();
function init(){
doSomething();
}
// extend.js
function extends init(){
doSomethingHereToo();
}
So I want to extend a function like I extend a class in PHP.
And I would like to extend it from other files too, so for example I have the original init function in main.js and the extended function in extended.js.
With a wider view of what you're actually trying to do and the context in which you're doing it, I'm sure we could give you a better answer than the literal answer to your question.
But here's a literal answer:
If you're assigning these functions to some property somewhere, you can wrap the original function and put your replacement on the property instead:
// Original code in main.js
var theProperty = init;
function init(){
doSomething();
}
// Extending it by replacing and wrapping, in extended.js
theProperty = (function(old) {
function extendsInit() {
old();
doSomething();
}
return extendsInit;
})(theProperty);
If your functions aren't already on an object, you'd probably want to put them there to facilitate the above. For instance:
// In main.js
var MyLibrary = {
init: function init() {
}
};
// In extended.js
(function() {
var oldInit = MyLibrary.init;
MyLibrary.init = extendedInit;
function extendedInit() {
oldInit.call(MyLibrary); // Use #call in case `init` uses `this`
doSomething();
}
})();
But there are better ways to do that. Like for instance, providing a means of registering init functions.
// In main.js
var MyLibrary = (function() {
var initFunctions = [];
return {
init: function init() {
var fns = initFunctions;
initFunctions = undefined;
for (var index = 0; index < fns.length; ++index) {
try { fns[index](); } catch (e) { }
}
},
addInitFunction: function addInitFunction(fn) {
if (initFunctions) {
// Init hasn't run yet, remember it
initFunctions.push(fn);
} else {
// `init` has already run, call it almost immediately
// but *asynchronously* (so the caller never sees the
// call synchronously)
setTimeout(fn, 0);
}
}
};
})();
Here in 2020 (or really any time after ~2016), that can be written a bit more compactly:
// In main.js
const MyLibrary = (() => {
let initFunctions = [];
return {
init() {
const fns = initFunctions;
initFunctions = undefined;
for (const fn of fns) {
try { fn(); } catch (e) { }
}
},
addInitFunction(fn) {
if (initFunctions) {
// Init hasn't run yet, remember it
initFunctions.push(fn);
} else {
// `init` has already run, call it almost immediately
// but *asynchronously* (so the caller never sees the
// call synchronously)
setTimeout(fn, 0);
// Or: `Promise.resolve().then(() => fn());`
// (Not `.then(fn)` just to avoid passing it an argument)
}
}
};
})();
There are several ways to go about this, it depends what your purpose is, if you just want to execute the function as well and in the same context, you can use .apply():
function init(){
doSomething();
}
function myFunc(){
init.apply(this, arguments);
doSomethingHereToo();
}
If you want to replace it with a newer init, it'd look like this:
function init(){
doSomething();
}
//anytime later
var old_init = init;
init = function() {
old_init.apply(this, arguments);
doSomethingHereToo();
};
The other methods are great but they don't preserve any prototype functions attached to init. To get around that you can do the following (inspired by the post from Nick Craver).
(function () {
var old_prototype = init.prototype;
var old_init = init;
init = function () {
old_init.apply(this, arguments);
// Do something extra
};
init.prototype = old_prototype;
}) ();
Another option could be:
var initial = function() {
console.log( 'initial function!' );
}
var iWantToExecuteThisOneToo = function () {
console.log( 'the other function that i wanted to execute!' );
}
function extendFunction( oldOne, newOne ) {
return (function() {
oldOne();
newOne();
})();
}
var extendedFunction = extendFunction( initial, iWantToExecuteThisOneToo );
2017+ solution
The idea of function extensions comes from functional paradigm, which is natively supported since ES6:
function init(){
doSomething();
}
// extend.js
init = (f => u => { f(u)
doSomethingHereToo();
})(init);
init();
As per #TJCrowder's concern about stack dump, the browsers handle the situation much better today. If you save this code into test.html and run it, you get
test.html:3 Uncaught ReferenceError: doSomething is not defined
at init (test.html:3)
at test.html:8
at test.html:12
Line 12: the init call, Line 8: the init extension, Line 3: the undefined doSomething() call.
Note: Much respect to veteran T.J. Crowder, who kindly answered my question many years ago, when I was a newbie. After the years, I still remember the respectfull attitude and I try to follow the good example.
This is very simple and straight forward. Look at the code. Try to grasp the basic concept behind javascript extension.
First let us extend javascript function.
function Base(props) {
const _props = props
this.getProps = () => _props
// We can make method private by not binding it to this object.
// Hence it is not exposed when we return this.
const privateMethod = () => "do internal stuff"
return this
}
You can extend this function by creating child function in following way
function Child(props) {
const parent = Base(props)
this.getMessage = () => `Message is ${parent.getProps()}`;
// You can remove the line below to extend as in private inheritance,
// not exposing parent function properties and method.
this.prototype = parent
return this
}
Now you can use Child function as follows,
let childObject = Child("Secret Message")
console.log(childObject.getMessage()) // logs "Message is Secret Message"
console.log(childObject.getProps()) // logs "Secret Message"
We can also create Javascript Function by extending Javascript classes, like this.
class BaseClass {
constructor(props) {
this.props = props
// You can remove the line below to make getProps method private.
// As it will not be binded to this, but let it be
this.getProps = this.getProps.bind(this)
}
getProps() {
return this.props
}
}
Let us extend this class with Child function like this,
function Child(props) {
let parent = new BaseClass(props)
const getMessage = () => `Message is ${parent.getProps()}`;
return { ...parent, getMessage} // I have used spread operator.
}
Again you can use Child function as follows to get similar result,
let childObject = Child("Secret Message")
console.log(childObject.getMessage()) // logs "Message is Secret Message"
console.log(childObject.getProps()) // logs "Secret Message"
Javascript is very easy language. We can do almost anything. Happy JavaScripting... Hope I was able to give you an idea to use in your case.
as I understand it, you are trying to fetch the applications connected to the user account. You can do this by making a request on the API, I don't know if discord.js covers this part of the API
endpoint: https://discord.com/api/users/#me/connections
Request type: GET Header:
Authorization: "Beareryou token"
response: [
{...}
]
Use extendFunction.js
init = extendFunction(init, function(args) {
doSomethingHereToo();
});
But in your specific case, it's easier to extend the global onload function:
extendFunction('onload', function(args) {
doSomethingHereToo();
});
I actually really like your question, it's making me think about different use cases.
For javascript events, you really want to add and remove handlers - but for extendFunction, how could you later remove functionality? I could easily add a .revert method to extended functions, so init = init.revert() would return the original function. Obviously this could lead to some pretty bad code, but perhaps it lets you get something done without touching a foreign part of the codebase.

Categories

Resources