How to store a weak reference to an object? [duplicate] - javascript

Is there any way in JavaScript to create a "weak reference" to another object? Here is the wiki page describing what a weak reference is. Here is another article that describes them in Java. Can anyone think of a way to implement this behavior in JavaScript?

Update: Since July, 2020 some implementations (Chrome, Edge, Firefox and Node.js) has had support for WeakRefs as defined in the WeakRefs proposal, which is a "Stage 3 Draft" as of December 16, 2020.
There is no language support for weakrefs in JavaScript. You can roll your own using manual reference counting, but not especially smoothly. You can't make a proxy wrapper object, because in JavaScript objects never know when they're about to be garbage-collected.
So your ‘weak reference’ becomes a key (eg. integer) in a simple lookup, with an add-reference and remove-reference method, and when there are no manually-tracked references anymore then entry can be deleted, leaving future lookups on that key to return null.
This is not really a weakref, but it can solve some of the same problems. It's typically done in complex web applications to prevent memory leakage from browsers (typically IE, especially older versions) when there is a reference loop between a DOM Node or event handler, and an object associated with it such as a closure. In these cases a full reference-counting scheme may not even be necessary.

When running JS on NodeJS, you may consider https://github.com/TooTallNate/node-weak.

Update: September 2019
It is not possible to use weak references yet, but most likely soon it will be possible, as WeakRefs in JavaScript are Work In Progress. Details below.
Proposal
Proposal in now in Stage 3 which means that it has complete specification and that further refinement will require feedback from implementations and users.
The WeakRef proposal encompasses two major new pieces of functionality:
Creating weak references to objects with the WeakRef class
Running user-defined finalizers after objects are garbage-collected, with the FinalizationGroup class
Use cases
A primary use for weak references is to implement caches or mappings holding large objects, where it’s desired that a large object is not kept alive solely because it appears in a cache or mapping.
Finalization is the execution of code to clean up after an object that has become unreachable to program execution. User-defined finalizers enable several new use cases, and can help prevent memory leaks when managing resources that the garbage collector doesn't know about.
Source and further reading
https://github.com/tc39/proposal-weakrefs
https://v8.dev/features/weak-references

2021 Update
WeakRef is now implemented in Chrome, Edge, and Firefox. Still waiting on Safari and some other holdouts.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef
May 2021 Update
It's now available on Safari thus all major browsers. See above.

Just for reference; JavaScript doesn't have it, but ActionScript 3 (which is also ECMAScript) does. Check out the constructor parameter for Dictionary.

Finally they are here. Not yet implemented in browsers, but soon to be.
https://v8.dev/features/weak-references

True weak references, no, not yet (but browser makers are looking at the subject). But here is an idea on how to simulate weak references.
You could build a cache which you drive your objects through. When an object is stored, the cache keeps a prediction of how much memory the object will take up. For some items, like storing images, this is straight forward to work out. For others this would be more difficult.
When you need an object, you then ask the cache for it. If the cache has the object, it is returned. If it is not there, then the item is generated, stored, and then returned.
The weak references are simulated by the cache removing items, when the total amount of predicted memory reaches a certain level. It will predict which items are least used based on how often they are retrieved, weighted by how long ago they were taken out. A 'calculation' cost could also be added, if the code that creates the item is passed into the cache as a closure. This would allow the cache to keep items which are very expensive to build or generate.
The deletion algorithm is key, because if you get this wrong then you could end up removing the most popular items. This would cause terrible performance.
As long as the cache is the only object with permanent references to the objects stored, then the above system should work pretty well as an alternative to true weak references.

Using a caching mechanism to emulate a weak reference, as JL235 suggested above, is reasonable. If weak references would exist natively, you would observe a behavior like this:
this.val = {};
this.ref = new WeakReference(this.val);
...
this.ref.get(); // always returns val
...
this.val = null; // no more references
...
this.ref.get(); // may still return val, depending on already gc'd or not
Whereas with a cache you would observe:
this.val = {};
this.key = cache.put(this.val);
...
cache.get(this.key); // returns val, until evicted by other cache puts
...
this.val = null; // no more references
...
cache.get(this.key); // returns val, until evicted by other cache puts
As a holder of a reference, you should not make any assumptions about when it refers to a value, this is no different using a cache

the proposal and some details https://github.com/tc39/proposal-weakrefs
Typescript copy/paste version
export class IterableWeakMap<T extends Object, V> {
weakMap = new WeakMap();
refSet = new Set<WeakRef<T>>();
finalizationGroup = new FinalizationRegistry(IterableWeakMap.cleanup);
static cleanup({ set, ref }: { set: Set<WeakRef<Object>>; ref: WeakRef<Object> }) {
set.delete(ref);
}
constructor(iterable?: Iterable<[T, V]>) {
if (!iterable) return;
for (const [key, value] of iterable) {
this.set(key, value);
}
}
set(key: T, value: V) {
const ref = new WeakRef<T>(key);
this.weakMap.set(key, { value, ref });
this.refSet.add(ref);
this.finalizationGroup.register(key, { set: this.refSet, ref }, ref);
}
get(key: T) {
const entry = this.weakMap.get(key);
return entry && entry.value;
}
delete(key: T) {
const entry = this.weakMap.get(key);
if (!entry) {
return false;
}
this.weakMap.delete(key);
this.refSet.delete(entry.ref);
this.finalizationGroup.unregister(entry.ref);
return true;
}
*[Symbol.iterator]() {
for (const ref of this.refSet) {
const key = ref.deref();
if (!key) continue;
const { value } = this.weakMap.get(key);
yield [key, value];
}
}
entries() {
return this[Symbol.iterator]();
}
*keys() {
for (const [key] of this) {
yield key;
}
}
*values() {
for (const [, value] of this) {
yield value;
}
}
}

EcmaScript 6 (ES Harmony) has a WeakMap object. Browser support amongst modern browsers is pretty good (the last 3 versions of Firefox, chrome and even an upcoming IE version support it).

http://www.jibbering.com/faq/faq_notes/closures.html
ECMAScript uses automatic garbage collection. The specification does not define the details, leaving that to the implementers to sort out, and some implementations are known to give a very low priority to their garbage collection operations. But the general idea is that if an object becomes un-referable (by having no remaining references to it left accessible to executing code) it becomes available for garbage collection and will at some future point be destroyed and any resources it is consuming freed and returned to the system for re-use.
This would normally be the case upon exiting an execution context. The scope chain structure, the Activation/Variable object and any objects created within the execution context, including function objects, would no longer be accessible and so would become available for garbage collection.
Meaning there are no weak ones only ones that no longer become available.

Related

WeakSet: garbage collection doesn't work? [duplicate]

The WeakSet is supposed to store elements by weak reference. That is, if an object is not referenced by anything else, it should be cleaned from the WeakSet.
I have written the following test:
var weakset = new WeakSet(),
numbers = [1, 2, 3];
weakset.add(numbers);
weakset.add({name: "Charlie"});
console.log(weakset);
numbers = undefined;
console.log(weakset);
Even though my [1, 2, 3] array is not referenced by anything, it's not being removed from the WeakSet. The console prints:
WeakSet {[1, 2, 3], Object {name: "Charlie"}}
WeakSet {[1, 2, 3], Object {name: "Charlie"}}
Why is that?
Plus, I have one more question. What is the point of adding objects to WeakSets directly, like this:
weakset.add({name: "Charlie"});
Are those Traceur's glitches or am I missing something?
And finally, what is the practical use of WeakSet if we cannot even iterate through it nor get the current size?
it's not being removed from the WeakSet. Why is that?
Most likely because the garbage collector has not yet run. However, you say you are using Traceur, so it just might be that they're not properly supported. I wonder how the console can show the contents of a WeakSet anyway.
What is the point of adding objects to WeakSets directly?
There is absolutely no point of adding object literals to WeakSets.
What is the practical use of WeakSet if we cannot even iterate through it nor get the current size?
All you can get is one bit of information: Is the object (or generically, value) contained in the set?
This can be useful in situations where you want to "tag" objects without actually mutating them (setting a property on them). Lots of algorithms contain some sort of "if x was already seen" condition (a JSON.stringify cycle detection might be a good example), and when you work with user-provided values the use of a Set/WeakSet would be advisable. The advantage of a WeakSet here is that its contents can be garbage-collected while your algorithm is still running, so it helps to reduce memory consumption (or even prevents leaks) when you are dealing with lots of data that is lazily (possibly even asynchronously) produced.
This is a really hard question. To be completely honest I had no idea in the context of JavaScript so I asked in esdiscuss and got a convincing answer from Domenic.
WeakSets are useful for security and validation reasons. If you want to be able to isolate a piece of JavaScript. They allow you to tag an object to indicate it belongs to a special set of object.
Let's say I have a class ApiRequest:
class ApiRequest {
constructor() {
// bring object to a consistent state, use platform code you have no direct access to
}
makeRequest() {
// do work
}
}
Now, I'm writing a JavaScript platform - my platform allows you to run JavaScript to make calls - to make those calls you need a ApiRequest - I only want you to make ApiRequests with the objects I give you so you can't bypass any constraints I have in place.
However, at the moment nothing is stopping you from doing:
ApiRequest.prototype.makeRequest.call(null, args); // make request as function
Object.create(ApiRequest.prototype).makeRequest(); // no initialization
function Foo(){}; Foo.prototype = ApiRequest.prototype; new Foo().makeRequest(); // no super
And so on, note that you can't keep a normal list or array of ApiRequest objects since that would prevent them from being garbage collected. Other than a closure, anything can be achieved with public methods like Object.getOwnPropertyNames or Object.getOwnSymbols. So you one up me and do:
const requests = new WeakSet();
class ApiRequest {
constructor() {
requests.add(this);
}
makeRequest() {
if(!request.has(this)) throw new Error("Invalid access");
// do work
}
}
Now, no matter what I do - I must hold a valid ApiRequest object to call the makeRequest method on it. This is impossible without a WeakMap/WeakSet.
So in short - WeakMaps are useful for writing platforms in JavaScript. Normally this sort of validation is done on the C++ side but adding these features will enable moving and making things in JavaScript.
(Of course, everything a WeakSet does a WeakMap that maps values to true can also do, but that's true for any map/set construct)
(Like Bergi's answer suggests, there is never a reason to add an object literal directly to a WeakMap or a WeakSet)
By definition, WeakSet has only three key functionalities
Weakly link an object into the set
Remove a link to an object from the set
Check if an object has already been linked to the set
Sounds more pretty familiar?
In some application, developers may need to implement a quick way to iterate through a series of data which is polluted by lots and lots of redundancy but you want to pick only ones which have not been processed before (unique). WeakSet could help you. See an example below:
var processedBag = new WeakSet();
var nextObject = getNext();
while (nextObject !== null){
// Check if already processed this similar object?
if (!processedBag.has(nextObject)){
// If not, process it and memorize
process(nextObject);
processedBag.add(nextObject);
}
nextObject = getNext();
}
One of the best data structure for application above is Bloom filter which is very good for a massive data size. However, you can apply the use of WeakSet for this purpose as well.
A "weak" set or map is useful when you need to keep an arbitrary collection of things but you don't want their presence in the collection from preventing those things from being garbage-collected if memory gets tight. (If garbage collection does occur, the "reaped" objects will silently disappear from the collection, so you can actually tell if they're gone.)
They are excellent, for example, for use as a look-aside cache: "have I already retrieved this record, recently?" Each time you retrieve something, put it into the map, knowing that the JavaScript garbage collector will be the one responsible for "trimming the list" for you, and that it will automatically do so in response to prevailing memory conditions (which you can't reasonably anticipate).
The only drawback is that these types are not "enumerable." You can't iterate over a list of entries – probably because this would likely "touch" those entries and so defeat the purpose. But, that's a small price to pay (and you could, if need be, "code around it").
WeakSet is a simplification of WeakMap for where your value is always going to be boolean true. It allows you to tag JavaScript objects so to only do something with them once or to maintain their state in respect to a certain process. In theory as it doesn't need to hold a value it should use a little less memory and perform slightly faster than WeakMap.
var [touch, untouch] = (() => {
var seen = new WeakSet();
return [
value => seen.has(value)) || (seen.add(value), !1),
value => !seen.has(value) || (seen.delete(value), !1)
];
})();
function convert(object) {
if(touch(object)) return;
extend(object, yunoprototype); // Made up.
};
function unconvert(object) {
if(untouch(object)) return;
del_props(object, Object.keys(yunoprototype)); // Never do this IRL.
};
Your console was probably incorrectly showing the contents due to the fact that the garbage collection did not take place yet. Therefore since the object wasn't garbage collected it would show the object still in weakset.
If you really want to see if a weakset still has a reference to a certain object then use the WeakSet.prototype.has() method. This method, as the name implies returns a boolean indicating wether the object still exists in the weakset.
Example:
var weakset = new WeakSet(),
numbers = [1, 2, 3];
weakset.add(numbers);
weakset.add({name: "Charlie"});
console.log(weakset.has(numbers));
numbers = undefined;
console.log(weakset.has(numbers));
Let me answer the first part, and try to avoid confusing you further.
The garbage collection of dereferenced objects is not observable! It would be a paradox, because you need an object reference to check if it exists in a map. But don't trust me on this, trust Kyle Simpson:
https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/es6%20%26%20beyond/ch5.md#weakmaps
The problem with a lot of explanations I see here, is that they re-reference a variable to another object, or assign it a primitive value, and then check if the WeakMap contains that object or value as a key. Of course it doesn't! It never had that object/value as a key!
So the final piece to this puzzle: why does inspecting the WeakMap in a console still show all those objects there, even after you've removed all of your references to those objects? Because the console itself keeps persistent references to those Objects, for the purpose of being able to list all the keys in the WeakMap, because that is something that the WeakMap itself cannot do.
While I'm searching about use cases of Weakset I found these points:
"The WeakSet is weak, meaning references to objects in a WeakSet are held weakly.
If no other references to an object stored in the WeakSet exist, those objects can be garbage collected."
##################################
They are black boxes: we only get any data out of a WeakSet if we have both the WeakSet and a value.
##################################
Use Cases:
1 - to avoid bugs
2 - it can be very useful in general to avoid any object to be visited/setup twice
Refrence: https://esdiscuss.org/topic/actual-weakset-use-cases
3 - The contents of a WeakSet can be garbage collected.
4 - Possibility of lowering memory utilization.
Refrence: https://www.geeksforgeeks.org/what-is-the-use-of-a-weakset-object-in-javascript/
##################################
Example on Weakset: https://exploringjs.com/impatient-js/ch_weaksets.html
I Advice you to learn more about weak concept in JS: https://blog.logrocket.com/weakmap-weakset-understanding-javascript-weak-references/

Is it ok to create a prototype just to save internal object properties?

When I instantiate an object in my javascript framework, I add a __listeners__ property to it. But then the console.log output shows the__listeners__ property first.
I don't want the __listeners__ property showing up in the beginning of the console.log output, since its an internal property in my framework. I'm looking for a way to somehow push the __listeners__ property to the end of the object.
The only solution I have so far is by adding an extra object in the prototype chain.
create: function() {
var objTemplate=Object.create(this);
var newObj=Object.create(objTemplate);
objTemplate.__listeners__=[];
return newObj;
}
But, the above solution, will cause slower lookups through the prototype chain and creates a slightly unintuitive object hierarchy.
Is this ok or is there a better solution to this problem?
If you can use ES2015's WeakMap, which cannot be shimmed on older environments (but see ¹), creating information related to an object that isn't stored on the object is one of their use cases:
const privateDataCache = new WeakMap();
class MyThingy {
constructor() {
privateDataCache.set(this, {listeners: []});
// ...
}
addListener(listener) {
privateDataCache.get(this).listeners.push(listener);
}
removeListener(listener) {
const data = privateDataCache.get(this);
data.listeners = data.listeners.filter(l => l !== listener);
}
}
Because the keys in a WeakMap are weakly-held, they don't prevent your objects from being garbage collected, and the private data stored in the WeakMap is removed when the key becomes invalid.
That won't work in IE prior to IE11, though. (And IE11's WeakMap is missing some things, but nothing the above relies on.)
¹ Although WeakMap cannot be correctly shimmed/polyfilled, the syntax can be shimmed/polyfilled. core.js does that, implementing the WeakMap by storing data on the key itself. So while not correct, it may well be what you want for your use case.

Can a JavaScript object's child reference itself?

I have a JavaScript object Team and a Score which represent points and some other functions. I want to know if it's safe to store the team in the score at the same time as storing the score in the team.
var Score = function(team){
this.team = team;
this.points = 0;
...
}
var team = {
name : 'Team 1',
}
team.score = new Score(team);
The result of this is that if I log team.score.team.score.team.score.team.score.team.score.points = 0. This is perfect for what I am programming, however does it represent a dangerous setup that may crash older browsers or cause any other issues? It looks exactly like an infinite loop however Chrome seems to be handling it fine.
Are there any reasons why I shouldn't do this?
Good question by the way.
This is called circular referencing.
Meaning the you are creating the nested reference of the same object.
Garbage collection in browsers: The main function of the garbage collector in the browser is to free the memory if the memory occupied by the object is no longer in use. But in the case of circular reference
An object is said to reference another object if the former has an
access to the latter (either implicitly or explicitly). For instance,
a JavaScript object has a reference to its prototype (implicit
reference) and to its properties values (explicit reference)
(Source MDN)
This is forcing the garbage collecting algorithm to prevent the object from being garbage collected, which in turn is a memory leak.
As per the MDN Mark and sweep algorithm is been improved in such circumstance of circular referencing which is intelligent enough to remove the object of this type.
Circular referencing was a problem in IE < 8 which caused the IE browsers to go hay wire on this. Read this link and this one
IBM link
This article sheds light on JavaScript circular referencing memory leak with example and clarity on the subject.
Final Verdict: Better to avoid circular referenced objects, only use when its highly needed at programmers discretion. As modern browsers today are quite efficiently built though but its not a good practice as a developer to write code that causes unwanted memory consumption and leaks.
Diagrammatic Represation For Circular Referencing
Consider the code snippet below:
const obj = {
id: 1
};
obj.cirRef = obj;
console.log(obj.cirRef === obj); // true
console.log(obj.cirRef.cirRef === obj); // true
console.log(obj.cirRef.cirRef.cirRef.cirRef.id); // 1
Here's a diagrammatic representation for the same:
Now using the diagram above, follow the wires and try to answer what this expression obj.cirRef.cirRef.id evaluates to, the answer is 1.
var Score = function(team,point){
this.team = team;
this.points = 0;
...
}
var team = {
name : 'Team 1',
point : 'point'
}
team.score = new Score(team);
team.score = new Score(point);
Try this, maybe it can help you

Javascript persistent-sorting Object "class"

Attending to it's specification, JSON elements (and javascript objects) are unordered so, even in almost all cases, when you iterate over a javascript object, you get elements in the same order they was defined; you definitively cannot trust in that order because engine is allowed to alter it.
This is extremely rare. I have been able to observe it one time, but I don't find that code right now and I don't remember the exact version of JS engine (but it was node). If I manage to find it, I will add it to this post.
That being said, the point is that code relying in this behaviour can (and should) be considered buggy because, even it will work as expected in most engines, it may fail typically because of internal engine optimisations.
For example:
"use strict";
var x = {
b: 23,
a: 7
};
function someSorting(input) {
var output = {};
Object.keys(input).sort().map(
function(k){
output[k] = input[k];
}
);
return output;
};
x = someSorting(x);
// Some smart engine could notice that input and output objects have the
// exact same properties and guess that, attending the unordered nature of
// javascript Object, there is no need to actually execute someSorting();
console.log(x);
// Usually will display: { a: 7, b: 23 }
// But perfectly we could got: { b: 23, a: 7 }
I know there is too many literature (even StackOverflow questions) about this (NON-) issue and "workarrounds" to achieve the expected behaviour by sorting keys in a separate array.
But doing so code goes too messy compared in simply trusting in key order.
I'm pretty sure that this can be achieved in a more elegant fashion by implementing a so-called "sObject" alternative having native Object as its prototype but overloading it's native iterator and setter so that:
When any new property is added, it's key is appended to an Array index mantained under the hood.
When an sObject instance is iterated, our customized iterator uses that index to retrieve elements in the right order.
In summary: Actual Object specification is right because, in most cases, properties order doesn't care. So I think that engine optimisations that could mess it are wonderfull.
But it would be also wonderful to have an alternative sObject with which we could do something like:
var x = new sObject({b: 23, a: 7});
...and trust that we could iterate it in the same exact order or, also / at least, do some sorting task over it and trust that this will not be altered.
Of course!! I'm initalyzing it with a native javascript Object so, in fact, theoretically we can't trust that it will be populated right (even I can't imagine why any engine optimisation should alter it before any operation).
I used that notation for brevity (and, I confess) because I expect that, in that case should work always (even I'm not really sure). However we even could sort it later (which, in most cases we will do that way) or use other kind of initialization like providing a JSON string or an array of objects (or arrays) with single key and value pairs.
My concern is: Such a thing exists yet? I wasn't able to find it. But sure I'm not the first guy thinking in that...
I can try to implement it (I'm thinking about that). I think it's possible and that I could achieve it. But it's not as simple so first I want to be sure that I'm not reinventing the wheel...
So any comments, suggestions, etc... will be welcome.
Sure, you could do all this. You will need some machinery such as Object.observer, which is currently only available in Chrome. We can define this as the following:
function myObject(object) {
// if the object already has keys, bring them in in whatever order.
var keys = Object.keys(object);
// Override Object.keys to return our list of keys.
Object.defineProperty(object, 'keys', { get: function() { return keys; });
// Watch the object for new or deleted properties.
// Add new ones at the end, to preserve order.
Object.observe(object, function(changes) {
changes.forEach(function(change) {
if (change.type === 'add') keys.push(change.name);
if (change.type === 'delete') keys = keys.filter(function(key) {
return key === change.name;
});
});
});
return object;
}
Note that Object.observe is asynchronous, so even after you add a property to the object, it won't be reflected in the custom keys property until after a tick of the clock, although in theory you could use Object.deliverChangedRecords.
The above approach uses a function which adds the new ordered key functionality to an existing object. Of course there are other ways to design this.
This "solution" obviously cannot control the behavior of for...in loops.

Javascript's equivalent of destruct in object model

Since I've dealt in the past with javascript's funky "object model", I assume there is no such thing as a destructor. My searches were mildly unsuccessful, so you guys are my last hope. How do you execute stuff upon instance destruction?
MDN is a nice resource for JS.
No, there is nothing like calling a function when an object ceases.
FinalizationRegistry might be what you need. It is not a destructor, but it executes a function once the object is garbage collected. In any case, this is what I wish I had find when I first came on here :)
As of more recently, this link is of more use to answer this question. The most important part:
As of 2012, all modern browsers ship a mark-and-sweep
garbage-collector.
...
Cycles are no longer a problem
In the first example above, after the function call returns, the two
objects are no longer referenced by any resource that is reachable
from the global object. Consequently, they will be found unreachable
by the garbage collector and have their allocated memory reclaimed.
Limitation: Releasing memory manually
There are times when it would be convenient to manually decide when
and what memory is released. In order to release the memory of an
object, it needs to be made explicitly unreachable.
So as far as cyclic references goes, de[con]structors aren't really needed.
One cool trick I have thought of though, if you have cyclic references and you want easy manual control over deconstruction...
class Container {
constructor() {
this.thisRef = [ this ];
this.containee = new Containee({ containerRef: this.thisRef });
}
//Note: deconstructor is not an actual JS thing/keyword.
deconstructor() {
//Have to delete `this.thisRef[0]` and not `this.thisRef`, in
//order to ensure Containee's reference to Container is removed.
delete this.thisRef[0];
}
doSomething() {
}
}
class Containee {
constructor({ containerRef }) {
//Assumption here is, if the Container is destroyed, so will the Containee be
//destroyed. No need to delete containerRef, no need for a
//deconstructor function!
this.containerRef = containerRef;
}
someFunc() {
this.containerRef[0].doSomething();
}
}
let c = new Container();
...
//No cyclic references!
c.deconstructor();
So here, instead of the Containee class storing a direct reference to the Container instance, it stores a reference to a size 1 array containing the Container reference, which the Container instance itself can then delete itself from. The array, with the reference, is managed by Container.
But again, this isn't really needed, since garbage collection in all modern browsers is mark-and-sweep and can handle cyclic references.
In other languages the destructor is handy for implementing the memento pattern. That's actually what lead me to this topic. For example, in a click event it'd be nice to have a generic function that I can pass the event target to that disables the target and then re-enables it when it falls out of scope. Consider a submit button that does something like this:
function async saveMyStuff(e) {
const sleeper = new nap(e)
let data = await fetch(...)
// a bunch more code.
}
class nap {
constructor(e) {
this.button = e.currentTarget
this.button.disabled = true
}
destructor() { this.button.enabled = true }
}
This kind of construct would give me a oneliner that handles enabling/disabling all of my buttons when I'm talking to the backend or doing any other processing. I don't have to worry about cleaning up if I return somewhere in the middle or anything like that.

Categories

Resources